najamjad-cop
Pursuit League — агент-полицейский 👮
Сторона полицейского в финальном проекте на двоих по курсу Orchestration of AI Agents: распределённая игра в «кошки-мышки» между двумя агентами, играемая peer-to-peer через MCP (FastMCP/HTTP) против агентов других команд, с целостностью commit-reveal на SHA-256 и отправкой результатов через Gmail API.
Репозиторий-компаньон (агент-вор): https://github.com/najikay/pursuit-thief-agent Общий базовый пакет байт-в-байт идентичен в обоих репозиториях, что обеспечивается
scripts/sync_core.pyв CI (см.docs/PLAN.md, ADR-002).
Команда: Naji Kayal · Amjad Abed
Статус: M6 — сыграно и подано шесть засчитанных серий против шести разных соперников,
порог прохождения правила 31 превышен трижды. Играет полную проверяемую серию, взаимодействует
с эталонным симулятором курса и с шестью независимыми реализациями команд, а после матча
проверяет игру соперника. Оставшаяся работа отслеживается в 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 |
Тридцать шесть из тридцати шести мини-игр получили Verified OK при проверке, в шести
засчитанных сериях, с нулём технических поражений по нашей вине. Именно на это число мы бы
указали в первую очередь: каждая сыгранная нами игра была такой, что обе стороны могли
пересчитать хэш и согласиться с результатом, включая две, которые мы крупно проиграли.
Две серии сверены поле-в-поле с собственным поданным отчётом соперника — у vibecode
по 66 полям с нулём расхождений, а позже товарищеская игра против anrbj666 совпала по всем
шести под-играм, по обоим значениям mutual_agreement.sha256 и по обеим парам github_commit
для каждого окна. Отчёт, совпадающий с отчётом соперника, — единственный, который нельзя
аннулировать по правилам 33–35, и для нас он ценнее, чем счёт на табло.
Содержание
Установка · Командная строка · Запуск · Рабочий процесс в день матча
Академический отчёт: модель · дилеммы оркестрации · стратегии · чему нас научило тестирование против незнакомца
Related MCP server: Police MCP Server
Установка
Требования
Python | 3.12+ (управляется через uv — предустанавливать не нужно) |
единственный используемый здесь менеджер пакетов (правила §8.4) | |
ОС | Linux, macOS или Windows через WSL2 — разрабатывалось на 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 verdictПрохождение check_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. Агент играет полную проверяемую серию на одних шаблонах (книга, стр. 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. Запустите peer-сервер с панелью управления
uv run najamjad-cop peer --dashboard --no-tunnelДождитесь Uvicorn running — именно это, а не первая строка журнала, означает готовность.
Холодный старт занимает ~15 с (импорт MCP-стека), так что в день матча запускайтесь заранее.
Затем откройте http://127.0.0.1:8000/.
Порт и хост берутся из config/setup.json (ui.port, ui.host). Панель привязана
к loopback намеренно: она показывает наши представления и наши запечатанные состояния,
поэтому её публикация отдала бы сопернику всё то, что commit-reveal существует, чтобы скрывать
(правила 8–9).
Что вы получаете:
Панель | Показывает |
Board | Тепловая карта представлений в логарифмическом масштабе — линейная сжала 47 из 48 ячеек в одну полосу |
Turn banner | Чей ход, какой шаг, какая фаза |
Dialogue | Все подсказки входящие и исходящие, с моделью, которая их написала |
Negotiation | Предложение → контрпредложение → фиксация, и условия, ожидающие человека |
Budget | Токены относительно согласованного лимита в 200k |
Match day | Готовность — те же проверки, что выполняет |
Testing | Режим практики и отвечает ли каждый эндпоинт |
Matches | Каждый поданный нами матч: счёт, вердикты проверки по играм, артефакты |
Events | Сырой поток событий |
Обновления приходят через WebSocket; клиент никогда не опрашивает. Сбой панели не может повлиять на игру — она лишь подписчик и ничего больше (ADR-005).
Дополнительные элементы управления. Установите features.controls в true в config/setup.json,
чтобы включить запуск/остановку, одобрение переговоров и переключатель режима практики
со страницы. По умолчанию выключено, и намеренно нет кнопки, которая играет засчитанный
матч — он оценивается и необратим, и docs/RUNBOOK.md является интерфейсом для него.
2b. Тестирование без обращения к преподавателю
Панель Testing отвечает на два вопроса, которые иначе означают копание в журналах.
В каком я режиме? Режим практики перенаправляет каждый отчёт в ваш собственный почтовый ящик
вместо ящика преподавателя и добавляет префикс [PRACTICE] к теме. Он не пропускает
отправку — отправка была тем шагом, на котором проигрывались матчи в задании 6, поэтому
практический прогон выполняет её по-настоящему, и вы читаете реальное письмо. Перенаправление
обеспечивается дважды: адрес переписывается, а затем проверяется в точке невозврата,
так что молчаливо неудачная перезапись вызывает исключение вместо доставки. См.
docs/CONFIG.md §3b.
Проще всего флаг — он включает практику для одного процесса и ничего не трогает:
uv run najamjad-cop match --opponent amjad --practice --dashboard --tunnelИли переключите его с панели (при включённом features.controls), или установите
practice.enabled в config/setup.json, чтобы сделать его постоянным. Он читается заново при каждой
сборке отчёта, так что переключатель действует без перезапуска, и он переопределяет
email.mode на send — практический прогон, который тихо создал черновик, выглядел бы
точно так же, как успешная отправка.
Кто-нибудь вообще доступен? Probe endpoints обращается к нашему 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, и переопределение одного из них для конкретного противника — это именно то,
что никогда не должно быть простым.
Или задайте network.opponent_url в config/police/game.toml вручную, затем:
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 — задайте
network.opponent_urlвconfig/police/game.toml.Игра —
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, который не видит ни одна сторона
Игра — это децентрализованный частично наблюдаемый марковский процесс принятия решений. Ни один агент не наблюдает истинное состояние: позиции запечатаны в обязательствах до финального аудита, поэтому каждый участник держит убеждение о том, где может быть другой, и действует на его основе.
Два канала наблюдения с противоположными свойствами доверия:
Запах — затухающий феромонный след, который противник испускает непроизвольно и не может подделать (книга, СТР. 22). Неподделываемый, но размытый.
Поставляются две модели, и на каждый матч можно выбрать любую. Книжная (СТР. 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, покадровый шлюз противника это измерил, и кадры теперь закреплены по ячейкам против обхода (test_wire_scent_serve_order.py). Так что подбор под противника — это один ключ —pheromones.pheromone_modelвconfig/game.json— и не изменение четырнадцати подписанных условий, поэтому дайджест контрактаa284082d…переживает переключение, и никому не нужно переподписывать. Дайджест, который мы объявляем при переговорах, берётся из сконфигурированной модели, так что не существует состояния, в котором мы передаём одну физику, а заявляем другую. Эмиссия отдельно регулируется от подсказок —--scent full|window|noneи--hints/--no-hints— так что полностью тихая серия — это один флаг; в режиме тишины мы не объявляем никакой модели вообще, потому что заявление о поле, которое никто не отправляет, — это не заявление, которое стоит делать.Подсказки — свободный естественный язык, которому правила явно разрешают быть ложью (правила 26–27). Точные, но ненадёжные.
Наш механизм убеждений объединяет их: диффузия для движения, обновление правдоподобия запаха и
вес достоверности для каждого противника, который растёт и падает по мере того, как их подсказки согласуются или расходятся со
следом. Полный вывод — в docs/PRD_belief_engine.md.
Три вывода из его построения, каждый из которых изменил дизайн:
Затухание запаха имело неподвижную точку. Относительное затухание, округлённое до трёх знаков, никогда не достигало нуля, поэтому мёртвые следы вечно загрязняли убеждение. Исправлено явным эпсилоном.
Мультипликативное слияние дважды учитывало кумулятивное поле запаха и оставляло убеждение отстающим от движущегося противника на ~5 ячеек. Заменено на устойчивое обновление смеси.
Плоское правдоподобие парковало убеждение в середине следа. Заострение плюс аддитивный минимум исправили это; ограничение делало слабый запах неотличимым от его отсутствия.
Дилеммы оркестрации
Один шлюз или много вызывающих? Правило книги 3 предписывает оркестратор, и мы поняли его буквально: периферийные модули никогда не вызывают друг друга. Механизм убеждений ничего не знает о транспорте, стратегия ничего не знает о криптографии, транспорт ничего не знает о правилах. Именно это делает весь цикл хода тестируемым против заглушек — шов, которого у Задания 6 никогда не было.
Насколько доверять заглушке. Наш самый острый урок. Три отдельных дефекта пережили 1500 прошедших тестов, потому что заглушки были добрее, чем канал: фиктивный транспорт, оборачивавший аудиторскую полезную нагрузку так, как настоящий не оборачивал, внутрипроцессная ссылка, которая никогда не блокировалась, и участники, которые играли только сами с собой. Интероперабельность можно проверить только против того, что вы не писали.
Куда поместить дедлайн. Участник, отвечающий вечно, не должен удерживать нас в решённой игре, а участник, замолчавший, не должен стать нашей технической потерей. Каждое ожидание ограничено, и каждое завершение объявляется, а не предполагается — см. ниже.
Ограничение скорости нашего собственного протокола. Привратник существует, чтобы быть хорошим гражданином по отношению к 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 % ДИ Уилсона |
наш коп против жадного вора | 60/60 | 100 % | 94–100 % |
жадный коп против нашего вора | 0/60 | 0 % (100 % выживание) | 0–6 % |
жадный против жадного (эталон) | 4/60 | 6.7 % | 2.6–16 % |
Ноль разногласий между пирами и ноль сбоев аудита во всех 180 играх.

Один настраиваемый параметр решает исход матча, и это не тот, который мы ожидали:

barrier_threshold меняет долю захватов с 4 % до 100 % во всём диапазоне. Барьер непроходим для обеих сторон, поэтому коп, который ставит стену на слабых основаниях, отгораживается от вора, которого преследует, — мы две недели поставляли 0.15, что стоило нам примерно трети игр. lookahead — настоящий нулевой результат: глубины 1–4 дают побайтово идентичные игры, потому что изотропное диффузионное ядро сохраняет ранжирование кандидатных ходов, которое оно должно разделять.
Оговорка, которую мы обязаны сделать. Наш вор выживает против каждого копа, с которым мы когда-либо сталкивались или которого архивировали, — и всё же проигрывает, примерно на шаге 30, нашему собственному запечатывающему копу, чей план половинного деления не показал ни один противник. Оба направления зафиксированы, а не сглажены (test_thief_beats_sealing_cops.py фиксирует поражение и его цену; наборы corner-hunt и archive фиксируют выживания), потому что вор, оценённый только против копов, которых он побеждает, оценён против самого себя.
Полные выводы, доверительные интервалы, таблица стоимости токенов и ссылки находятся в 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, которое их парсер отвергает наотрез, и три поля claim, типы которых различались. Затем выяснилось, что аудит-раскрытие отправляется как простой список, тогда как схема объявляет конверт, поэтому оба пира записали TAMPERED для игр, в которых никто не жульничал.
Каждая из этих проблем проходила наши собственные тесты. Ядро commit-reveal, напротив, пережило контакт без изменений: наш commit_of воспроизводит сигнатуру эталона байт в байт.
Урок, который мы вынесли для любого распределённого проекта: зелёный набор тестов доказывает, что ваш код согласуется с вашими предположениями, а не то, что ваши предположения верны.
Документация
Документ | Назначение |
| Требования к продукту (идентификаторы FR-*, KPI, вехи) |
| Архитектура: диаграммы C4 + FSM, ADR-001..021, карта модулей |
| План сборки из 688 задач с трассируемостью и прогрессом |
| Текущее состояние, открытые вопросы и каждое измеренное исправление |
| Что пересекает провод, а что никогда |
| Модель угроз, защита от prompt-инъекций, обработка секретов |
| Эвристики Нильсена, сопоставленные с решениями дашборда; доступность |
| Четыре точки расширения с рабочим плагином |
| Каждый ключ конфигурации, его файл и его согласуемость по Приложению F |
| Что проверяет каждый шлюз и как воспроизвести сбой |
| Соглашения: синхронизация ядра, коммиты, тесты, заморозка в день матча |
| Характеристики качества ISO/IEC 25010, сопоставленные с доказательствами |
| Каждое обработанное граничное условие, каждое со ссылкой на свой тест |
| Измеренное потребление токенов и модель затрат |
| Что известно как неполное, с доказательствами |
| Исследования чувствительности, базовые уровни, таблица затрат, ссылки |
| Проектирование механизмов |
| Процедуры туннеля и подключения |
| Дайджесты источников (книга, руководства, эталонный симулятор, ретроспектива A6) |
Аудит противника
Commit-reveal доказывает, что пир не переписывал историю. Он ничего не доказывает о том, играли ли они по правилам, и это разные гарантии — мы смешивали их на протяжении всего этапа лиги и не могли сказать после проигранной серии, была ли игра легальной.
Аудит по замыслу проводится после матча: правила 33–35 аннулируют матч при противоречивых отчётах, поэтому агент, действующий на основании собственного обвинения, превращает подозрение во взаимный ноль. Всё ниже фиксирует доказательства и ничего не меняет в том, как мы играем (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, и нигде нет проверки захвата барьером или обездвиживания. Каждый противник, которого мы встречали, происходит из эталона, поэтому окружение даёт мини-игру, которую мы засчитываем, а они — нет — противоречие правил 33–35. Каждый захват должен быть заявлением, которое вор подтверждает (PLAN ADR-020).
Один коп не может сойтись на открытой доске. Сетка 7×7 — это декартово произведение двух путей, поэтому её число копов равно 2 (Maamoun & Meyniel, 1987), и исчерпывающая неподвижная точка по всем состояниям 49×49 не находит ни одного состояния, из которого коп, использующий только движение, может вынудить захват при одновременных ходах. Наш коп, преследующий вора до дистанции 2 и удерживающий её 28 шагов, — это теорема, а не дефект. Барьеры — единственный ресурс, который меняет ответ (PLAN ADR-021).
А с планом барьеры действительно меняют это. Запечатывание половинным делением превращает любого реагирующего вора, которого может построить стенд, — доска делится пополам, половина делится пополам, 3×3 решается точно, заканчиваясь заявлением о совместном нахождении в пределах 35 ходов. Два указанных выше ограничения по-прежнему управляют формой этой победы: она должна заканчиваться заявлением, которое вор подтверждает, и её нельзя получить только движением. То, что долго фиксировалось здесь как наш самый большой конкурентный риск — коп, который преследует до дистанции 2 и удерживает, — закрыто; остающийся риск — это противник, чей собственный коп играет по плану, столь же полному, как наш, и именно против этого оцениваются нижние границы вора.
tests/regression/cop_duel.py — это эталон со стороны копа, с помощью которого проверяются эти утверждения: наш коп против адаптивного вора, с убеждением, которое реальный путь входа строит по запаху. Записанная линия противника не реагирует и не может измерить сближение.
Лицензия и атрибуция
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