«Codex» против «Claude»: здесь речь идет не столько о поиске единого универсального победителя, сколько о выборе стиля работы, которому вы сможете доверять каждый день. Оба продукта позволяют анализировать репозиторий, редактировать несколько файлов, запускать команды, выполнять тесты и объяснять содержание патча. Существенные различия заключаются в том, как вы делегируете работу, как часто управляете агентом, какой объем данных вы можете анализировать и насколько каждый из инструментов вписывается в вашу существующую среду разработки.
В ходе нашего контролируемого тестирования на репозитории с четырьмя задачами Codex набрал 98 из 100 баллов, а Claude Code — 99 из 100. Оба решения выполнили основную работу. Claude Code продемонстрировал более широкий обзор и охват пограничных случаев, в то время как Codex в нашей конфигурации часто достигал требуемого результата с меньшим объемом работ и предоставлял более убедительные доказательства на уровне выполнения. Разница в один балл в небольшом тестовом наборе на Python не является основанием для объявления общего победителя.
Разработчики, которые не хотят, чтобы остальная часть их рабочего процесса была привязана к одному кодирующему агенту, могут добавить GlobalGPT в качестве отдельного мультимодельного и мультимодального слоя. GlobalGPT объединяет более 100 ведущих моделей, таких как GPT 5.6, Claude Opus 5 и GPT Image 2, в одной панели управления. Кроме того, GlobalGPT CLI, MCP и Skill routes можно использовать на основе Codex или Claude Code для получения второго мнения, планирования, документирования или работы с другими поддерживаемыми моделями, в то время как собственная среда разработки сохраняет контроль над изменениями в репозитории и тестированием.

В рамках данного сравнения объединены данные из официальных документации, результаты практической работы с репозиториями, полные расширяемые наборы данных и четко описанный опыт сообщества. Цель состоит в том, чтобы помочь независимому разработчику выбрать основную платформу для программирования, не запутываясь в вопросах доступа по подписке, дополнительных кредитов и тарификации API.
Краткий обзор кода «Codex» и «Claude»
| Решающий фактор | Кодекс | Код Клода |
|---|---|---|
| Основная работа с репозиторием | Считывает, редактирует, выполняет команды и проверяет изменения на всех поддерживаемых поверхностях Codex | Диалоговый терминальный агент для просмотра, редактирования, запуска команд и проверки изменений |
| Стиль, зафиксированный в ходе нашего тестирования | Более компактный в плане реализации отдельных компонентов и исправления ошибок | Более тщательный анализ репозиториев, тестирование и широкий охват рецензирования |
| Понимание репозитория | Функциональная связь с «замороженной» задачей | |
| Обзор кода | Обнаружены и устранены два действительных дефекта более высокой степени серьезности | Сообщил о дополнительных воспроизводимых проблемах и изменил оценку с 19/20 на 18/20 |
| Замеченная скорость | Результаты неоднозначные; условия не были достаточно сопоставимыми, чтобы определить единого победителя | |
| Начальный сегмент потребительского рынка | $20 в месяц в рамках соответствующего плана ChatGPT | Claude Pro: $20 в месяц в США |
| Уровни с более интенсивным использованием | Уровни $100 и $200 | Максимум 5x при $100 и максимум 20x при $200 |
В таблице приведены данные, отражающие решение о покупке, а не рейтинг моделей. Результаты могут измениться в зависимости от настроек модели, репозитория, конфигурации прав доступа или спецификации задачи. Если вы уже используете какой-либо продукт, наиболее точным сравнением будет ограниченная задача из вашей собственной кодовой базы с той же командой успеха и без повторных прогонов для проверки качества.
Профиль контролируемого тестирования
Первый достоверный результат, та же фиксированная шкала оценки. Столбцы приведены к максимальному баллу по каждому заданию.
На графике показано, откуда взялась эта разница в одно очко; он не превращает небольшой турнир в универсальный рейтинг.
Что на самом деле представляют собой Codex и код Claude
Codex и Claude Code — это названия продуктов, а не просто названия моделей. В основе лежит Модель искусственного интеллекта для программирования имеет значение, но окружающая инфраструктура также определяет, какие файлы доступны агенту, какие команды он может выполнять, как работает система утверждений, как сохраняется контекст и какие данные остаются после завершения задачи. Если сравнивать только репутацию модели, то при этом игнорируется значительная часть опыта, который приобретает разработчик.
Codex охватывает рабочие процессы, реализуемые в командной строке, в IDE, на рабочем столе и в облаке. Такой широкий спектр возможностей делает его подходящим как для прямого локального сотрудничества, так и для более ограниченного делегирования задач. Claude Code ориентирован на диалоговый рабочий процесс в терминале с поддержкой интеграций и обширными возможностями настройки; это руководство по использованию Claude для кодирования содержит более подробное введение в этот рабочий процесс. Некоторым разработчикам успокаивает наблюдение за работой агента в терминале. Для других же важнее всего не непрерывный диалог, а итоговый дифф, тесты и журнал аудита.
Это различие также объясняет, почему два теста, использующие номинально мощные модели, могут демонстрировать разное поведение. Хост определяет, как отображаются инструкции, как вызываются инструменты и когда человек должен утвердить то или иное действие. При сравнении в сообществе, в котором не учитывается тестовая среда, поведение на уровне продукта можно ошибочно принять за истину на уровне модели.
- Модель обеспечивает возможности для логического обоснования и генерации.
- Комплект проводов датчиков управляет файлами, командами, контекстом, утверждениями и восстановлением.
- Контракт на выполнение задачи пользователя определяет область действия, условия успешного выполнения и момент, когда агент должен прекратить работу.

Рабочий процесс и управление: делегирование полномочий или постоянное руководство?
Самый полезный вопрос при сравнении Codex и Claude Code зачастую заключается не в том, “что позволяет писать лучший код?”, а в том, “как я хочу с ним работать?” Четкую, ограниченную задачу можно делегировать, указав точную цель, допустимый объем работ и команду проверки. В случае неоднозначного рефакторинга полезно провести обсуждение, промежуточную проверку и дать возможность перенаправить исполнителя, пока он не внес слишком много изменений.
Постоянное управление оправдывает себя, когда требования меняются или архитектурные решения ещё находятся в стадии согласования. Оно становится излишней тратой ресурсов, когда агент неоднократно запрашивает решения, которые можно было бы принять на основании инструкций из репозитория. Автономное выполнение оправдывает себя, когда условия задачи остаются неизменными. Оно становится рискованным, когда агент делает непроверенные допущения или расширяет рамки задачи без четкого плана отката.
В одном подробном отчете на Reddit от 13 апреля 2026 года описывается опыт работы с Claude Code в течение примерно 100 часов и с Codex — 20 часов над проектом на Python и TypeScript, состоящим из примерно 80 000 строк кода и включающим около 2 800 тестов. Автор охарактеризовал Claude как более быстрый и интерактивный инструмент, но требующий большего внимания, а Codex — как более медленный и продуманный. Этот отчёт необычайно полезен, поскольку в нём представлен контекст проекта и опыта, но он всё же отражает рабочий процесс только одного разработчика.

Наши собственные тесты не позволили выявить однозначного победителя. Claude выполнил первые два задания быстрее, тогда как Codex — последние два. Кроме того, Claude прибег к использованию резервного субагента после того, как его путь аутентификации через CLI оказался недоступен, поэтому маршруты выполнения не были эквивалентны лабораторным условиям. Обоснованный вывод заключается в том, что скорость зависит от задачи, выбранной модели, настроек интенсивности, контекста и хоста — а не в том, что какой-либо из продуктов всегда работает быстрее.
Понимание репозитория и управление контекстом
Понимание репозитория — это нечто большее, чем просто присвоение имен папкам. Полезный агент должен отслеживать, как данные перемещаются между файлами, выявлять контракты, ограничивающие изменения, находить тесты, отличать симптом от его вероятного источника и объяснять риск редактирования не того уровня. Исчерпывающая карта может выявить скрытые несоответствия; лаконичная карта же поможет разработчику быстрее принять безопасное решение о реализации.
В нашей задаче T1, предполагающей только чтение, оба агента набрали 20 из 20 баллов и обосновали свои ответы ссылками на репозиторий. Код Claude был более исчерпывающим и выявил дополнительные несоответствия в контракте. Codex был более лаконичным, но при этом также определил соответствующие файлы, риски и план реализации. Ни один из этих стилей не является автоматически лучшим. Исчерпывающий подход полезен при миграциях и аудитах в незнакомой среде; лаконичный подход — когда разработчик уже знаком с архитектурой и нуждается в четком плане изменений.
T1 · Тестирование контролируемого репозитория
Прежде чем вносить изменения в незнакомый репозиторий, ознакомьтесь с ним
Создайте схему архитектуры, проследите поток данных, определите риски, связанные с приоритетными функциями, и не вносите никаких изменений в файлы.
Архитектура: модель, репозиторий, сервис и утилита «unwired time». Основные риски: неопределённая семантика приоритетов, несовместимость, нарушение порядка, проверка достоверности и несоответствие области применения.
Мнение рецензента: Краткое, основанное на материалах дела и достаточное для вынесения окончательного решения.
Три уровня плюс один «сиротский» модуль. Отсутствие циклов; минимальная инъекция зависимостей. Кроме того, выявились проблемы с распределением идентификаторов, асимметричными контрактами ошибок и недостаточным тестовым покрытием.
Мнение рецензента: Более исчерпывающий, при этом по-прежнему соответствующий тому же соглашению о доступе только для чтения.
Просмотреть полный вывод Codex
Полный очищенный первый допустимый вывод
Архитектура ##
Это небольшой пакет Python, использующий исключительно стандартную библиотеку, состоящий из четырёх функциональных уровней:
- **Модель данных:** [`Job`]() — это неизменяемый класс данных (dataclass), содержащий `identifier`, `name` и `owner`. `Job.to_dict()` сериализует его с помощью `dataclasses.asdict()`.
- **Репозиторий:** [`JobRepository`]() хранит задания в словаре в памяти, ключом которого служит идентификатор. База данных или долгосрочное сохранение данных отсутствуют.
- **Сервис:** [`SchedulerService`]() отвечает за присвоение идентификаторов, нормализацию входных данных, создание, отображение в списке и удаление заданий.
- **Утилита времени:** [`next_daily_run()`]() вычисляет время следующего запуска, но ничто не импортирует её и не связывает с `Job`, `SchedulerService` или `JobRepository`.
- **Публичный API:** [`scheduler.__init__`]() экспортирует только `SchedulerService`.
Несмотря на название репозитория, задания в настоящее время не содержат информации о планировании, и очереди выполнения не существует. Поэтому приоритет может влиять на сохраненные метаданные и порядок отображения в списке, но не может повлиять на фактическое выполнение задания без значительного расширения системы.
## Поток данных при создании и отображении в списке
Создание с помощью `SchedulerService.create_job(name, owner)`:
1. [`create_job()`]() отклоняет имя, состоящее исключительно из пробелов.
2. Функция обрезает `name` и `owner`, а затем создаёт неизменяемый объект `Job`, используя `_next_identifier` сервиса.
3. [`JobRepository.save()`]() записывает объект в `_jobs[job.identifier]`.
4. Сервис увеличивает значение `_next_identifier` и возвращает тот же объект `Job`.
Вывод списка с помощью `SchedulerService.list_jobs()`:
1. [`list_jobs()`]() напрямую делегирует вызов `repository.all()`.
2. [`JobRepository.all()`]() сортирует ключи словаря по числовому значению.
3. Поэтому задания возвращаются в порядке возрастания идентификатора/времени создания, а не в порядке расписания или приоритета.
## Файлы, на которые, вероятно, повлияют приоритеты заданий
Требуется:
- [`scheduler/models.py`](): добавить поле приоритета и любое значение по умолчанию. `to_dict()` автоматически включит его, поскольку использует `asdict()`.
- [`scheduler/service.py`](): принимать, проверять и передавать приоритет в `Job`.
- [`tests/test_scheduler.py`](): проверить поведение при значении по умолчанию, явном указании, недопустимом значении, сериализации и сортировке.
Условно:
- [`scheduler/repository.py`](): изменить `all()` только в том случае, если приоритеты предназначены для управления порядком в списке. Детерминированный вторичный ключ, такой как `identifier`, должен обрабатывать случаи равенства.
- [`scheduler/__init__.py`](): обновлять только в том случае, если приоритет станет публичным перечислением или объектным значением.
- [`README.md`](): задокументируйте допустимые значения, значение по умолчанию и семантику упорядочивания.
Вероятно, не затронуто:
- `scheduler/time_rules.py`, поскольку его единственный символ оперирует заданным датой и временем и не имеет отношения к заданиям или отображению списка.
## Основные риски
- **Неопределённая семантика:** В коде нет никаких указаний на то, означают ли большие или меньшие значения более высокий приоритет, какие значения являются допустимыми, или влияет ли приоритет на порядок отображения в списке вообще.
- **Совместимость:** Добавление обязательного аргумента в `Job` или `create_job()` приведёт к сбою существующих вызывающих функций, таких как `create_job("Daily report", "Alex")` в текущем тесте. Значение по умолчанию сохраняет возможность такого вызова.
- **Нарушение позиционного конструктора:** в настоящее время объект `Job` создаётся с использованием позиционного конструктора в `SchedulerService.create_job()`. Расположение полей и будущие позиционные вызовы могут незаметно присваивать неверные значения; использование ключевого слова при создании было бы более безопасным.
- **Изменение порядка:** Замена порядка идентификаторов в `JobRepository.all()` изменяет устоявшееся поведение. При равных приоритетах требуется стабильный механизм определения порядка.
- **Неоднозначность валидации:** Неограниченное значение Python может допускать строки, булевы значения или произвольные целые числа, которые сложно сравнивать последовательно.
- **Несоответствие области выполнения:** Отсутствует диспетчер или очередь выполнения. Утверждение о том, что приоритет определяет, какая задача выполняется первой, не поддерживается ни одним из существующих символов.
- **Ограничения в памяти:** приоритет, как и любое другое поле задания, исчезает при завершении процесса, поскольку `_jobs` является лишь словарём экземпляра.
## План реализации и валидации
1. Сначала определить контракт: представление, допустимые значения, значение по умолчанию, направление приоритета, порядок при равенстве значений и влияние на порядок в списке.
2. Добавить `priority` в `Job`, предпочтительно с обратно совместимым значением по умолчанию.
3. Расширить `SchedulerService.create_job()`, добавив параметр приоритета с значением по умолчанию, проверить его и создать `Job` с помощью ключевых аргументов.
4. Если при выводе списка учитывается приоритет, измените `JobRepository.all()` так, чтобы сначала сортировать по приоритету, а затем по идентификатору. В противном случае оставьте порядок в репозитории без изменений.
5. Добавьте тесты для:
- Существующего создания с двумя аргументами.
- Сохранения явно указанного приоритета.
- Приоритета по умолчанию.
- Недопустимый тип и значения, выходящие за пределы диапазона.
- Вывод `Job.to_dict()`.
- Порядок отображения при наличии нескольких приоритетов.
- Стабильный порядок при равных приоритетах.
- Существующее поведение при пустом имени.
6. Обновите файл README, указав точный публичный контракт.
7. Запустить полный набор автономных тестов с помощью `python3 -m unittest discover -s tests -v`.
## Проверка выполнена
- Базовый набор тестов: **2 теста пройдено**.
- Поиск символов по всему репозиторию подтвердил, что `next_daily_run()` отключен и существующих символов приоритета нет.
- Измененные файлы: **нет**.
- Реализация функции: **не выполнена**, как и требовалось.
> **Вывод + решение**
>
> Изменение незначительно, если приоритет является лишь метаданными или определяет порядок в списке: в основном `models.py`, `service.py`, `repository.py` и тесты. Перед реализацией необходимо принять решение о том, описывает ли приоритет лишь задание или изменяет порядок в `list_jobs()`, а также о шкале значений, значении по умолчанию, направлении и правиле при равенстве значений.Просмотреть полный вывод кода Claude
Полная запись передачи, включая дословный текст первого корректного вывода
Запись выполнения # T1 — Анализ неизвестного репозитория
Параметры выполнения ##
| Поле | Значение |
| --- | --- |
| Задача | `T1` |
| Замороженный запрос | `01-prompts/T1.md` |
| SHA-256 замороженного промпта | `a571ff15c2502ec29b172ae2e77dd9ab0caca2869b91f9468d47571434d16c17` |
| Блок выполнения | изолированный субагент Claude, `general-purpose`, новый контекст |
| Метод изоляции | **резервный вариант субагента** (документированное понижение версии — см. `results/isolation-decision.md`) |
| Назначенная чистая копия | `runtime/workspaces/T1` |
| Версия кода Claude | `2.1.220` |
| Настройки модели | `claude-opus-5` |
| start_utc | `2026-07-28T10:27:31Z` |
| end_utc | `2026-07-28T10:28:32Z` |
| Продолжительность | 61 с (одновременно с T2–T4; не является точным измерением задержки) |
| Номер попытки | 1 |
| Статус | `valid` |
| Вмешательство человека | нет |
## Сводка по инструменту Safe
`date`, `find`, `ls`, `wc`, `stat`, `grep`, `Read` на 7 файлах рабочей области, `python3 -V`,
`python3 -m unittest discover -s tests -v`. Все операции чтения ограничены назначенной рабочей областью.
Без сети, без установок, без записей.
## Результат автономной проверки
`python3 -m unittest discover -s tests -v` → 2 теста, OK (код завершения 0). Повторно проверено
координатором из-за пределов рабочей области: см. `results/checks/T1-public.txt`.
## Патч
Нет. Файл `results/T1/patch.diff` пуст, а команда `diff -ru 02-fixture runtime/workspaces/T1`
не выдает никаких различий. Задача требовала проверки без изменения файлов; это
подтверждено, а не просто заявлено.
## Очищенные ошибки
Одна устранимая ошибка оболочки: в начальном вызове `grep` использовался не заключённый в кавычки шаблон `--include=*.py`, который
оболочка попыталась интерпретировать как глобальный; при повторном запуске с шаблонами в кавычках операция прошла успешно. На результаты проверки это не повлияло.
## Видимый вывод (дословно)
### 1. Что представляет собой этот репозиторий
Автономный фикстур стандартной библиотеки Python с именем `local-scheduler-1.0.0` (`fixture-manifest.json`), распространяемый по лицензии MIT, без сетевых или производственных зависимостей (`README.md`, `"network_required": false`). Он очень небольшой: 8 файлов исходного кода и документации плюс манифест, всего 103 строки. Используется интерпретатор **Python 3.9.6**. Здесь нет файлов `pyproject.toml`, `setup.py`, конфигурации CI, линтера или конфигурации средства проверки типов — единственный объявленный рабочий процесс: `python3 -m unittest discover -s tests -v` (`README.md`).
### 2. Архитектура
Три уровня плюс один отдельный модуль, все в каталоге `scheduler/`:
| Уровень | Файл | Символ | Ответственность |
|---|---|---|---|
| Фасад пакета | `scheduler/__init__.py` | `__all__ = ["SchedulerService"]` | Переэкспортирует только `SchedulerService`; `Job`, `JobRepository` и `time_rules` не входят в публичный интерфейс |
| Доменная модель | `scheduler/models.py` | `Job` (`@dataclass(frozen=True)`) | Неизменяемый объект-значение с полями `identifier: int`, `name: str`, `owner: str`, а также методом `to_dict()`, реализованным как `asdict(self)` |
| Сохранение | `scheduler/repository.py` | `JobRepository` | `dict` в памяти с ключом по идентификатору; `save`, `get`, `all`, `delete` |
| Сервис приложения | `scheduler/service.py` | `SchedulerService` | Проверка, присвоение идентификаторов, оркестрация: `create_job`, `list_jobs`, `delete_job` |
| Осиротевший | `scheduler/time_rules.py` | `next_daily_run` | Арифметика повторяющихся задач — **не импортируется ничем** |
Направление зависимостей чёткое и одностороннее: `service.py` импортирует из `.models` и `.repository`; `repository.py` импортирует из `.models`; `models.py` импортирует только `dataclasses`. Циклов нет. Инъекция зависимостей присутствует, но минимальна — `SchedulerService.__init__(self, repository=None)` выполняет `self.repository = repository or JobRepository()`, поэтому в тестах можно подставить фиктивный репозиторий.
Обратите внимание, что `scheduler/time_rules.py` на сегодняшний день является мёртвым кодом. Я просканировал всё дерево на наличие `time_rules` и `next_daily_run`; единственные совпадения — это его собственное определение и упоминание в `expected_files` файла `fixture-manifest.json`. Он включён в дистрибутив, но не подключён.
### 3. Поток данных
**Создание задания** — `SchedulerService.create_job(name, owner)`:
1. Проверка: `if not name.strip(): raise ValueError('name is required")`. Это *единственная* проверка в системе — `owner` никогда не проверяется, поэтому допускается пустое значение владельца.
2. Создание: `Job(self._next_identifier, name.strip(), owner.strip())` — позиционное создание, при этом обе строки нормализуются путем удаления лишних символов.
3. Сохранение: `self.repository.save(job)`, что выполняет `self._jobs[job.identifier] = job` и возвращает задание.
4. Инкремент счётчика: `self._next_identifier += 1` — *после* сохранения, поэтому возникшее исключение оставляет счётчик неиспользованным.
5. Возврат экземпляра `Job` (сервис возвращает свой собственный локальный `job`, а не возвращаемое значение репозитория).
Присвоение идентификаторов происходит в **сервисе**, а не в репозитории (`self._next_identifier = 1` в `SchedulerService.__init__`). Это важный момент: инъекция репозитория, уже содержащего задания, незаметно перезапишет их, поскольку новый сервис начинает нумерацию с 1.
**Вывод списка заданий** — `SchedulerService.list_jobs()` представляет собой прямой вызов `JobRepository.all()`, который возвращает `[self._jobs[key] for key in sorted(self._jobs)]`. Поэтому сортировка происходит **по возрастанию по целочисленному идентификатору**, что на данный момент совпадает с порядком вставки. При каждом вызове создаётся новый список, но объекты `Job` являются общими ссылками — это безопасно только потому, что класс `Job` заморожен.
**Удаление** — `SchedulerService.delete_job(identifier)` делегирует вызов `JobRepository.delete`, который представляет собой `self._jobs.pop(identifier)` без значения по умолчанию, поэтому при отсутствии идентификатора генерирует исключение `KeyError`. Это несовместимо с `JobRepository.get`, который возвращает `None` при том же условии.
**Покрытие тестами этих путей** — В файле `tests/test_scheduler.py` есть ровно два тестовых случая: `test_create_and_list_jobs` (проверяет `job.identifier == 1` и `[job] == service.list_jobs()`) и `test_blank_name_is_rejected`. Оба проходят в текущем дереве.
### 4. Файлы, на которые, вероятно, повлияет добавление приоритетов заданий
В порядке убывания степени вероятности:
1. **`scheduler/models.py`** — наверняка. `Job` требуется поле `priority`. Поскольку dataclass имеет `frozen=True`, а поля являются позиционными, новое поле должно иметь значение по умолчанию (например, `priority: int = 0`) или быть размещено после трёх существующих полей; в противном случае нарушится работа всех существующих позиционных конструкций. Функция `to_dict()` не требует изменений — `asdict(self)` автоматически извлекает это поле, что является незаметным изменением контракта сериализации, а не изменением кода.
2. **`scheduler/service.py`** — точно. Функции `create_job` требуется параметр `priority`, и его необходимо передать в позиционный конструктор `Job(...)` в строке 13. Если приоритет проверяется (диапазон, принадлежность к перечислению), условие проверки должно располагаться рядом с существующей проверкой `name.strip()`. Если список должен быть отсортирован по приоритету, функция `list_jobs` — это место, где должна находиться политика сортировки, если вы хотите, чтобы репозиторий оставался "простым хранилищем'.
3. **`scheduler/repository.py`** — вероятно. В `sorted(self._jobs)` функции `JobRepository.all()` сортируются *ключи* словаря, т. е. идентификаторы. Для сортировки списка по приоритету необходимо изменить это так, чтобы сортировать значения по ключу, например `(-job.priority, job.identifier)`, или добавить отдельный упорядоченный аксессор. Не оставляйте разрыв при равных значениях неявным: порядок вставки в словарь не является стабильным соглашением, на которое можно полагаться.
4. **`tests/test_scheduler.py`** — точно. Новые тестовые случаи для приоритета по умолчанию, явного приоритета, упорядочивания и отклонения заданий с недопустимым приоритетом. Обратите внимание, что существующий `assertEqual([job], service.list_jobs())` сравнивает *тот же* объект, поэтому он сохраняет работоспособность при добавлении поля; он перестал бы работать, если бы сравнивал только что созданный литерал `Job`.
5. **`README.md`** — вероятно, если семантика приоритетов (какой конец диапазона имеет преимущество, значение по умолчанию) должна быть где-либо указана.
6. **`scheduler/__init__.py`** — только если необходимо экспортировать перечисление приоритетов или константы вместе с `SchedulerService`.
7. **`fixture-manifest.json`** — только если вы добавляете новый файл модуля; его массив `expected_files` представляет собой явный перечень и может измениться.
8. **`scheduler/time_rules.py`** — к нему *не* следует прикасаться. Приоритет не зависит от периодичности, и этот модуль не подключён.
### 5. Основные риски
- **Семантика сортировки представляет собой скрытое изменение поведения.** `JobRepository.all()` в настоящее время гарантирует упорядочение по идентификаторам в восходящем порядке, и `list_jobs` наследует это поведение. Любой потребитель, полагающийся на эту гарантию, столкнётся с проблемами из-за-сортировкой. Необходимо явно определиться: меняет ли `list_jobs()` своё значение, или наряду с ним появляется новый метод `list_jobs_by_priority()`? Первый вариант сопряжён с более высоким риском, а существующий тест `test_create_and_list_jobs` слишком слаб, чтобы обнаружить регрессию (список с одним элементом).
- **Направление сортировки действительно неоднозначно.** "Приоритет 1" по соглашению означает *самый высокий* в одних системах и *самый низкий* — в других. В этом репозитории нет ничего — ни комментариев, ни docstring, ни строчки в README — что бы это уточняло. Выберите соглашение, задокументируйте его в `models.py` и заложите в тест с использованием как минимум трёх различных приоритетов, чтобы направление сортировки было фиксированным.
- **Нестабильная сортировка при равных приоритетах.** Если два задания имеют одинаковый приоритет, результат всё равно должен быть детерминированным. Функция `sorted` в Python является стабильной, но стабильность имеет смысл только в том случае, если сам порядок входных данных определён. Всегда включайте `identifier` в качестве явного вторичного ключа.
- **Порядок полей в `frozen-dataclass`.** `Job` является классом `@dataclass(frozen=True)` с тремя позиционными полями, и в `service.py:13` он создаётся с учётом позиций. Вставка `priority` в любом месте, кроме последнего, или без значения по умолчанию, является изменяющим поведение изменением, которое два существующих теста могут не выявить явно.
- **Расширение контракта `to_dict()`.** `asdict(self)` отражает все поля. Добавление `priority` изменяет каждый сериализованный набор данных без видимых изменений в теле метода в `models.py`. Любые проверки на точную структуру словаря перестанут работать.
- **Ограничения Python 3.9.6.** Отсутствует `@dataclass(slots=True)` (3.10+), отсутствует `kw_only=True` (3.10+), а аннотации PEP 604 `int | None` приводят к сбоям во время выполнения без `from __future__ import annotations`. Если приоритет моделируется как перечисление, то `enum.StrEnum` доступно только в версии 3.11 и выше и недоступно. Любой из этих факторов приведёт к сбою фикстуры в данном интерпретаторе.
- **Распределение идентификаторов находится на неправильном уровне.** `SchedulerService._next_identifier` означает, что сервис отвечает за генерацию идентификаторов, в то время как репозиторий отвечает за хранение. Если работа с приоритетами потребует реализации второго репозитория или предварительно загруженных фикстур, такое разделение приведет к коллизиям идентификаторов и перезаписи заданий.
- **Асимметричные контракты ошибок.** `JobRepository.get` возвращает `None` при отсутствии, тогда как `JobRepository.delete` генерирует исключение `KeyError`. Любой новый поиск, связанный с приоритетом, должен сознательно выбирать одну из этих конвенций, а не случайно унаследовать эту несогласованность.
- **Прецедент с пробелом в валидации.** `create_job` проверяет `name`, но не `owner`. Не следует копировать такую небрежность в отношении `priority` — непроверенный приоритет проникает в ключ сортировки и может вызвать исключение `TypeError` глубоко внутри функции `sorted` (например, при сравнении `int` с `None`), а не в месте вызова.
- **Ловушка мёртвого кода.** Файл `scheduler/time_rules.py` выглядит как логика планирования и будет привлекать внимание редакторов. Он никуда не импортируется, а в его собственном docstring признаётся наличие ошибки: он добавляет 24 прошедших часа в формате UTC и 'сдвигает время по местным часам при переходе на летнее время". Его изменение не оказывает никакого заметного влияния на тестируемую систему, поэтому усилия, затраченные на это, тратятся впустую, а любой тест, написанный для него, не проверяет ничего из того, что попадает в релиз.
- **Тонкая сеть безопасности.** Два теста, нет CI, нет линтера, нет проверки типов. Нет ничего, что могло бы поймать регрессию, кроме того, что вы напишете сами. Рассматривайте существующий набор тестов как недостаточное базовое покрытие, а не как контрольный барьер.
### 6. План реализации (не выполнен)
1. **Сначала определите семантику в письменной форме.** Тип приоритета (`int` или перечисление), допустимый диапазон, значение по умолчанию для существующих/неуказанных заданий и направление сортировки. Зафиксируйте это в виде docstring для класса `Job` в файле `scheduler/models.py` — это единственное место, от которого уже зависят все уровни.
2. **Расширьте модель.** Добавьте `priority: int = 0` в качестве *последнего* поля класса `Job` в файле `scheduler/models.py`, сохранив позиционную совместимость с `service.py:13` и не изменяя `to_dict()`.
3. **Внедрите его в сервис.** Добавьте параметр `priority` с значением по умолчанию в `SchedulerService.create_job`, проверьте его рядом с существующим условием `name.strip()` (вызывайте исключение `ValueError`, соответствующее установленному типу ошибки) и передайте его в конструктор `Job`.
4. **Явно определите контракт на получение списка заданий.** Предпочтительный вариант с низким риском: оставьте `JobRepository.all()` без изменений в качестве примитива, упорядоченного по идентификаторам, и добавьте отдельный аксессор, упорядоченный по приоритету. Если же значение функции `list_jobs()` должно измениться, измените выражение-понимание в `JobRepository.all()` так, чтобы значения сортировались по явному составной ключу, включающему `identifier` в качестве критерия при равенстве значений, и отметьте это изменение в файле `README.md`.
5. **Синхронизируйте файл `scheduler/__init__.py`** только в том случае, если был введён общедоступный перечислитель или константа.
6. **Не трогайте файл `scheduler/time_rules.py`** и не добавляйте файлы, если в рамках одного и того же изменения не обновляется поле `expected_files` в файле `fixture-manifest.json`.
### 7. План валидации
- **Сначала базовый тест.** Перед любым редактированием запустите `python3 -m unittest discover -s tests -v` и убедитесь, что оба теста прошли успешно. Я уже сделал это — всё прошло без ошибок.
- **Контроль регрессии.** Оба существующих теста должны по-прежнему проходить без изменений. Если тест `test_create_and_list_jobs` требует редактирования, это сигнал о том, что изменение нарушает работоспособность, а не повод для редактирования теста.
- **Новые тестовые случаи в `tests/test_scheduler.py`:**
- Приоритет по умолчанию при вызове `create_job` со старой сигнатурой с двумя аргументами (подтверждает обратную совместимость).
- Явное определение приоритета при прохождении цикла `create_job` → `list_jobs`.
- Сортировка с **тремя или более** различными приоритетами, проверка полного списка — именно это определяет направление сортировки.
- Разрешение ничьи: два задания с равным приоритетом возвращаются в порядке возрастания идентификаторов.
- Недопустимый приоритет вызывает исключение `ValueError`, как и в случае с пустым именем.
- `to_dict()` включает `priority` с ожидаемым значением.
- Путь к встроенному репозиторию: `SchedulerService(repository=fake)` по-прежнему правильно назначает приоритет, используя шв `repository or JobRepository()`.
- **Проверка совместимости.** Убедитесь, что всё работает именно на Python 3.9.6 — без `slots=`, без `kw_only=`, без простых объединений по PEP 604, без `StrEnum`.
- **Проверка инвентаря.** Перечитайте файл `fixture-manifest.json` и убедитесь, что набор файлов на диске по-прежнему соответствует `expected_files`.
- **Детерминизм.** Запустите набор тестов два или три раза; ошибки, связанные с порядком итерации по словарю, могут проявляться периодически.
- **Чистота.** Запустите с параметром `PYTHONDONTWRITEBYTECODE=1`, чтобы каталоги `__pycache__` не отображались в манифесте как неотслеживаемые отклонения.
Ограничение тестовой среды: речь шла о небольшом автономном репозитории на Python. В Claude после истечения срока действия OAuth через CLI использовался резервный вариант с суб-агентом, поэтому изоляция и видимость токена не совпадали.
Этот результат не отражает производительность при работе с крупным монорепозиторием или в ходе недельной автономной сессии. Тестовая среда была намеренно создана небольшой и контролируемой. Для реальной оценки начните с режима «только для чтения»: попросите каждый инструмент отобразить путь вызова, указать файлы, которые он изменит, определить тесты и перечислить нерешенные допущения, прежде чем разрешить редактирование.
Стиль реализации, область применения патча и исправление ошибок
Работа с несколькими файлами
Одинаковое поведение при прохождении тестов может быть результатом разных инженерных решений. В тесте T2 оба продукта набрали 30/30 и прошли тест «frozen hidden validator». В реализации Claude проверка была размещена на нескольких границах, а также были добавлены более широкие тесты прямой модели и пороговые тесты. В реализации Codex использовалась более компактная сервис-ориентированная реализация, которая также соответствовала контракту.
Для независимого разработчика это настоящий компромисс. Более широкая валидация позволяет защитить инварианты, когда объекты создаются по разным путям. Меньший по размеру патч может сократить площадь регрессии и время рецензирования, если в качестве предполагаемой точки входа выбран один сервис. Правильный ответ зависит от правил владения репозиторием, а не от отдельного подсчёта изменившихся строк или тестов.
T2 · Тестирование контролируемого репозитория
Реализовать приоритетную функцию в нескольких файлах
Добавьте функцию «заморозки», обеспечьте совместимость и пройдите проверки как открытых, так и скрытых элементов.
Добавлена приоритетность в неизменяемую модель, проверена на границе сервиса и сохранен порядок в репозитории. Все семь публичных тестов и зафиксированный скрытый валидатор прошли успешно.
Мнение рецензента: Более компактная реализация, ориентированная на обслуживание, которая обеспечивала выполнение всех зафиксированных моделей поведения.
Проверено соответствие приоритетам как на границе службы, так и в неизменяемой модели, сохранена фильтрация репозитория и добавлено покрытие пороговых значений. Пройдены четырнадцать открытых тестов и скрытый валидатор.
Мнение рецензента: Более широкий охват прямой модели и пороговых значений без преимущества по функциональному баллу.
Просмотреть полный вывод Codex
Полный очищенный первый допустимый вывод
Реализована функция приоритета запланированных заданий. Измененные файлы: - [scheduler/models.py](./scheduler/models.py:5) — добавлен сериализуемый параметр `priority`, значение по умолчанию — `0`. - [scheduler/service.py](./scheduler/service.py:11) — добавлены проверка, сохранение и фильтрация `list_jobs(min_priority=0)` с сохранением порядка идентификаторов. - [tests/test_scheduler.py](./tests/test_scheduler.py:16) — добавлено покрытие для значений по умолчанию, сериализации, хранения, границ, недопустимых значений и фильтрации. Запуск тестов: ```text python3 -m unittest discover -s tests -v Выполнено 7 тестов — OK ``` **Вывод:** Замороженная задача завершена и проверена. **Требуемое решение:** Нет.
Просмотреть полный вывод кода Claude
Полная запись передачи, включая дословный текст первого корректного вывода
Запись выполнения # T2 — функция приоритета нескольких файлов Параметры выполнения # | Поле | Значение | | --- | --- | | Задача | `T2` | | Замороженный промпт | `01-prompts/T2.md` | | SHA-256 замороженного подсказки | `8476a56034c4e719b97ee4081b32b4c73efd45feafe1bda9d477c83cb8fdb698` | | Блок выполнения | изолированный субагент Claude, `universal`, новый контекст | | Метод изоляции | **резервный вариант субагента** (документированное понижение версии — см. `results/isolation-decision.md`) | | Назначенная чистая копия | `runtime/workspaces/T2` | | Версия кода Claude | `2.1.220` | | Настройки модели | `claude-opus-5` | | start_utc | `2026-07-28T10:27:52Z` | | end_utc | `2026-07-28T10:29:33Z` | | Продолжительность | 101 с (одновременно с T1, T3, T4; не является точным измерением задержки) | | Номер попытки | 1 | | Статус | `valid` | | Вмешательство человека | нет | ## Сводка по безопасному инструменту `date`, `Read`/`Edit`/`Write` только внутри назначенной рабочей области, `grep`, `python3 -m unittest discover`, `python3 -m compileall`, встроенные проверки `python3 -c`. Без сети, без установок, только стандартная библиотека. ## Измененные файлы `scheduler/models.py`, `scheduler/repository.py`, `scheduler/service.py`, `tests/test_scheduler.py`. Файлы не добавлялись и не удалялись, поэтому `fixture-manifest.json` остаётся точным. Полный патч: `results/T2/patch.diff`. ## Результаты автономной проверки Сообщение от исполнителя задач: | Проверка | Результат | | --- | --- | | `python3 -m unittest discover -s tests -v` (исходное состояние, до изменения) | 2 прошло, 0 не прошло | | `python3 -m compileall -q scheduler tests` | без ошибок | | встроенные тесты на работоспособность (устаревшая конструкция с 3 аргументами, пороговое значение для ключевых слов/позиционных аргументов, `to_dict`) | пройдено | | `python3 -m unittest discover -s tests -v` (итоговый результат) | **14 пройдено, 0 не пройдено** | Независимо перепроверено координатором из-за пределов рабочей области: | Проверка | Выход | Результат | | --- | --- | --- | | общедоступный набор тестов (`results/checks/T2-public.txt`) | 0 | 14 тестов, OK | | скрытый валидатор `03-checks/test_t2_hidden.py` (`results/checks/T2-hidden.txt`) | 0 | 2 теста, OK | Скрытый валидатор завершает работу с ошибкой (код завершения 1) при проверке исходной копии фикстуры, что подтверждает значимость успешного прохождения. См. `results/checks/validator-controls.md`. ## Покрытие поведения по золотому стандарту Все пять обязательных поведений в `03-checks/gold-map.json` выполнены: | Обязательное поведение | Доказательство | | --- | --- | | приоритет по умолчанию 0 | `Job.priority: int = MIN_PRIORITY`; `create_job(..., priority=MIN_PRIORITY)`; `test_priority_defaults_to_zero` | | диапазон целых чисел от 0 до 9 | `validate_priority` отклоняет нецелые значения и значения вне диапазона; `test_out_of_range_priority_is_rejected`, `test_non_integer_priority_is_rejected` | | сериализованный приоритет | `to_dict()` через `asdict`; `test_priority_appears_in_serialized_output` проверяет наличие точного словаря | | фильтрация по минимальному приоритету | `list_jobs(min_priority=0)` → `JobRepository.all(min_priority)`; `test_filter_is_inclusive_of_the_threshold` | | упорядочение по идентификаторам | фильтр применяется внутри существующего компренсирования `sorted(self._jobs)`; `test_filter_preserves_ascending_identifier_order` | ## Очищенные ошибки Нет. Артефакты `__pycache__`, оставшиеся после запусков тестов, были удалены средством запуска задач; проверка координатора подтвердила, что рабочая область очищена. ## Видимый вывод (дословно) Добавлено целочисленное поле `priority` к запланированным заданиям на всех уровнях — модели, репозитория и службы — в фикстуре локального планировщика, а также в отфильтрованном списке. **`scheduler/models.py`** — Добавлены константы модуля `MIN_PRIORITY = 0` / `MAX_PRIORITY = 9` и многократно используемая функция `validate_priority(priority)`, которая генерирует исключение `ValueError` для нецелых чисел и значений, выходящих за пределы диапазона от 0 до 9 включительно. Тип `bool`, несмотря на то что он является подклассом `int`, явно отклоняется, поэтому значение `True` не может проскользнуть в качестве приоритета 1. Замороженный класс данных `Job` получает поле `priority: int = MIN_PRIORITY` в конце списка полей с значением по умолчанию, что позволяет сохранить работоспособность существующего конструктора с тремя аргументами, а также метод `__post_init__`, который вызывает валидатор, благодаря чему создание недопустимых приоритетов по любому пути становится невозможным. `to_dict()` оставлено в виде `asdict(self)`, поэтому приоритет автоматически появляется в сериализованном выводе в порядке полей. **`scheduler/repository.py`** — `JobRepository.all()` принимает необязательный аргумент `min_priority` и выполняет фильтрацию в рамках существующего компренсинга `sorted(self._jobs)`, благодаря чему восходящий порядок по идентификаторам гарантируется тем же единственным кодовым путем, который уже обеспечивал его ранее, а не восстанавливается заново после фильтрации. Аргумент по умолчанию сохраняет прежнее поведение без аргументов для существующих вызывающих сторон. Само хранилище не требовало изменений: репозиторий хранит целые экземпляры `Job`, поэтому приоритет сохраняется и передаётся при вызовах `save`/`get`/`all`. **`scheduler/service.py`** — `create_job` принимает необязательный конечный аргумент `priority` (по умолчанию 0) и проверяет его перед созданием `Job`, поэтому исключение генерируется на границе сервиса с тем же контрактом `ValueError`, что и при существующей проверке на отсутствие имени. `list_jobs(min_priority=0)` делегирует вызов репозиторию. Сортировка и фильтрация реализованы в одном месте, а не дублируются. **Примечание по проектированию проверки `min_priority`:** он проверяется на тип как целое число, но намеренно *не* ограничивается диапазоном 0–9. Правило 0–9 ограничивает то, что может храниться в задании; пороговое значение является параметром запроса, и отклонение, например, `min_priority=10` превратило бы легитимный запрос "не найти ничего" в ошибку. Тест проверяет, что `list_jobs(min_priority=9)` возвращает `[]`, если ни одна задача не имеет приоритета 9. Файл `scheduler/time_rules.py` был прочитан, но оставлен без изменений — описанное в документации переключение на летнее время является существующим по умолчанию поведением, выходящим за рамки данной задачи, и его изменение привело бы к не связанному с ней изменению поведения. Файлы не добавлялись и не удалялись, поэтому файл `fixture-manifest.json` остаётся точным (проверено программно). ### Добавлено тестовое покрытие Значение по умолчанию 0; цикл чтения-записи через `JobRepository`; приоритет в выводе `to_dict()`; граничные значения 0 и 9 приняты; значения вне диапазона −1/10/100 отклонены; нецелые значения `"3"`/`3.5`/`None`/`True` отклонены; прямая валидация на уровне модели; нефильтрованный порядок перечисления; отфильтрованный список с сохранением порядке идентификаторов по возрастанию; пороговое значение, включающее граничные значения; пустой результат; нецелое значение `min_priority` отклонено.
Ограничение тестовой среды: речь шла о небольшом автономном репозитории на Python. В Claude после истечения срока действия OAuth через CLI использовался резервный вариант с суб-агентом, поэтому изоляция и видимость токена не совпадали.
Исправление ошибок в крайних случаях
T3 проверил дефект в расписании, связанный с переходом на летнее время. Оба агента набрали 30/30 баллов и прошли одинаковые скрытые проверки весной и осенью. В коде Claude было добавлено явное покрытие для неоднозначных и пропущенных значений местного времени, наивных входных данных и многодневных переходов. Codex внес более узкое изменение в календарный день и прошел проверку по «замороженному» контракту.
Более широкие тесты на крайние случаи дают уверенность в тех случаях, когда библиотека широко используется или цена ошибки планирования высока. Узкое исправление целесообразно, когда дефект хорошо изолирован, а команда стремится свести к минимуму изменения в поведении. Практический вопрос при рецензировании заключается не в том, “кто написал больше кода?”, а в том, устраняет ли патч указанную первопричину, сохраняет ли он окружающие контракты и проверяет ли он рискованные границы.
T3 · Тестирование контролируемого репозитория
Корректировка ежедневного расписания при переходе на летнее и зимнее время
Сохраняйте заданное время по нью-йоркским настенным часам во время перехода на летнее и зимнее время.
Основная причина: в результате внедрения было добавлено 24 часа по UTC. Исправление: переход на один местный календарный день вперед. Обе фиксированные проверки — весенняя и осенняя — прошли успешно.
Мнение рецензента: Более узкая по охвату поправка была принята в полном объеме.
Рассмотрены случаи весны и осени, пропущенные и неоднозначные значения местного времени, некорректные входные данные и многодневные переносы. Обе «замороженные» скрытые проверки прошли успешно после расширения охвата регрессионного тестирования.
Мнение рецензента: Более широкий охват крайних случаев; тот же функциональный балл по фиксированной шкале оценки.
Просмотреть полный вывод Codex
Полный очищенный первый допустимый вывод
Внесено исправление, связанное с переходом на летнее время. Измененные файлы: - [scheduler/time_rules.py](./scheduler/time_rules.py) - [tests/test_time_rules.py](./tests/test_time_rules.py) Изменения: - Переход на один календарный день вперёд вместо 24 часов по UTC. - Добавлены регрессионные тесты для перехода на летнее и зимнее время в Нью-Йорке. - Проверено, что промежутки времени по UTC составляют 23 и 25 часов соответственно. Проверки: - Модульные тесты: 4 пройдено. - Проверка синтаксиса в памяти: 7 файлов Python прошли успешно. - Компиляция байт-кода была заблокирована, поскольку Python перенаправляет свой кэш за пределы выделенного рабочего пространства; внешние файлы не записывались. **Вывод:** `next_daily_run` теперь сохраняет запрашиваемый час по реальному времени при переходе на летнее и зимнее время. Принятие решения не требуется.
Просмотреть полный вывод кода Claude
Полная запись передачи, включая дословный текст первого корректного вывода
Протокол выполнения # T3 — исправление ошибки DST
Параметры выполнения ##
| Поле | Значение |
| --- | --- |
| Задача | `T3` |
| Замороженный запрос | `01-prompts/T3.md` |
| SHA-256 замороженного подсказки | `3fee50d0230f27f8d6dd7f12e050fa3f0b7f5fb77d9559361fee96e5f1a47307` |
| Блок выполнения | изолированный субагент Claude, `general-purpose`, новый контекст |
| Метод изоляции | **резервный вариант субагента** (документированное понижение версии — см. `results/isolation-decision.md`) |
| Назначенная чистая копия | `runtime/workspaces/T3` |
| Версия кода Claude | `2.1.220` |
| Настройки модели | `claude-opus-5` |
| start_utc | `2026-07-28T10:28:05Z` |
| end_utc | `2026-07-28T10:30:03Z` |
| Продолжительность | 118 с (одновременно с T1, T2, T4; не является точным измерением задержки) |
| Номер попытки | 1 |
| Статус | `valid` |
| Вмешательство человека | нет |
## Краткий обзор инструмента Safe
`date`, `Read`/`Edit` только внутри назначенной рабочей области, `python3 -m unittest discover`,
`python3 -m compileall`, запуск с отрицательным контролем в памяти, проверка целостности манифеста.
Только стандартная библиотека (`datetime`, `zoneinfo`, `unittest`). Без сети, без установок.
## Измененные файлы
`scheduler/time_rules.py` (исправление — только тело и docstring функции `next_daily_run`),
`tests/test_scheduler.py` (добавлены `NextDailyRunTests`, 8 тестов, а также вспомогательная функция `_elapsed`;
существующие тесты не изменены). Другие модули не затрагивались, файлы не добавлялись. Полный патч:
`results/T3/patch.diff`.
## Результаты автономной проверки
Сообщение от средства запуска задач:
| Проверка | Результат |
| --- | --- |
| `python3 -m unittest discover -s tests -v` | **10 прошли, 0 не прошли** (2 существующих + 8 новых) |
| `python3 -m compileall -q scheduler tests` | без ошибок |
| целостность манифеста по сравнению с `fixture-manifest.json` | 0 отсутствующих, 0 неожиданных |
| отрицательный контроль: исправленная реализация с исходными данными в памяти, только `NextDailyRunTests` | 8 запущено, **5 завершились с ошибкой, как и ожидалось**, включая оба теста DST |
Независимо перепроверено координатором из-за пределов рабочей области:
| Проверка | Выход | Результат |
| --- | --- | --- |
| общедоступный набор тестов (`results/checks/T3-public.txt`) | 0 | 10 тестов, OK |
| скрытый валидатор `03-checks/test_t3_hidden.py` (`results/checks/T3-hidden.txt`) | 0 | 2 теста, OK |
Скрытый валидатор завершает работу с ошибкой (код завершения 1) при проверке исходной копии фикстуры. См.
`results/checks/validator-controls.md`.
## Покрытие поведения по золотой карте
Все четыре обязательных поведения, указанных в `03-checks/gold-map.json`, выполнены:
| Обязательное поведение | Доказательство |
| --- | --- |
| Сохранение часа по настенным часам | Приращение применено к простым локальным настенным часам, зона присоединена заново; проверяется в каждом тесте перехода на летнее время |
| Переход на весеннее время покрыт | `test_spring_forward_keeps_requested_hour` — час 09:30 сохранен, смещение `-04:00`, прошло 23 ч |
| Охвачен переход на осеннее время | `test_fall_back_keeps_requested_hour` — час 09:30 сохранен, смещение `-05:00`, прошло 25 ч |
| Использован часовой пояс IANA | `ZoneInfo("America/New_York")` из стандартной библиотеки |
Помимо требуемого набора, тестовый запуск также охватил два пограничных случая PEP 495 — реальное время,
пропущенное при переходе на летнее время, и неоднозначное реальное время во время перехода на зимнее время — а также семидневные циклы,
охватывающие каждый переход, и поведение при наивном вводе.
## Исправленные ошибки
Два сбоя тестовых утверждений, вызванных собственной ошибкой: оператор `following - previous` при работе с двумя датами и временами, имеющими общий
`tzinfo`, вычитает "наивные" значения реального времени, поэтому утверждения о прошедшем времени показывали 1 день и завершились сбоем.
Реализация была правильной, а проверки — ошибочными; исправлено с помощью вспомогательной функции `_elapsed`,
которая сначала преобразует оба операнда в UTC. Ошибок инструментов, импорта или среды не было.
Артефакты `__pycache__` были удалены после запуска.
## Видимый вывод (дословно)
**Воспроизведение**
Функция `scheduler/time_rules.py::next_daily_run` вызывалась с датой и временем в формате `America/New_York` по обе стороны от перехода на летнее время в 2024 году:
```
2024-03-09T09:30:00-05:00 -> 2024-03-10T10:30:00-04:00 #: часовой сдвиг +1
2024-11-02T09:30:00-04:00 -> 2024-11-03T08:30:00-05:00 #: смещение часа на -1
```
Задание, запланированное на 09:30 по местному времени, запустилось в 10:30 после перехода на летнее время и в 08:30 после перехода на зимнее время.
**Основная причина**
В исходной реализации «daily» рассматривалось как фиксированная абсолютная продолжительность:
```python
elapsed = previous_run.astimezone(timezone.utc) + timedelta(hours=24)
return elapsed.astimezone(previous_run.tzinfo)
```
Преобразование сначала в UTC приводит к тому, что `timedelta(hours=24)` равняется ровно 24 прошедшим часам. Однако местный календарный день в зоне IANA составляет 23 часа в день перевода часов вперёд и 25 часов в день перевода часов назад, поэтому постоянное смещение в 24 часа неизбежно приводит к отклонению на один час от запрашиваемого времени по настенным часам.
**Исправление** (`scheduler/time_rules.py`)
Ежедневная повторяемость является календарным правилом, поэтому приращение теперь применяется к «наивному» местному времени по часам, а зона привязывается позже:
```python
tzinfo = previous_run.tzinfo
naive_next = previous_run.replace(tzinfo=None) + timedelta(days=1)
if tzinfo is None:
return naive_next
candidate = naive_next.replace(tzinfo=tzinfo, fold=0)
return candidate.astimezone(timezone.utc).astimezone(tzinfo)
```
Почему это правильно:
- Арифметические операции с «наивным» значением, основанные на «настенных часах», не зависят от смещения, поэтому запрашиваемое значение «час:минута» сохраняется по самой сути алгоритма; затем `zoneinfo` предоставляет смещение UTC, действующее на новую дату (проверено: `-04:00` после перехода на летнее время, `-05:00` после перехода на зимнее время, прошедшее реальное время — 23 ч и 25 ч соответственно).
- `fold=0` в сочетании с циклом UTC обрабатывает два крайних случая, которые при использовании чистой арифметики реального времени остаются неопределёнными. Согласно PEP 495, *пропущенное* время по часам (02:30 10.03.2024) имеет смещение, действовавшее до перехода, при `fold=0`, поэтому цикл «туда-обратно» нормализует его до реального момента 03:30 EDT, а не возвращает datetime, не указывающий конкретного момента. *Неоднозначное* реальное время (01:30 03.11.2024) детерминированно преобразуется в его первое появление (EDT), а не становится произвольным.
- Простой входной параметр сохраняет прежнее значение (просто +1 календарный день) — на вызывающие функции не налагаются новые требования `tzinfo`.
Область изменений осталась узкой: изменились только тело функции и docstring `next_daily_run`. Файлы `service.py`, `models.py`, `repository.py` и `__init__.py` остались без изменений, новых файлов не добавлено, а манифест фикстур по-прежнему точно совпадает (нет отсутствующих или неожиданных файлов). Используется только стандартная библиотека (`datetime`, `zoneinfo`, `unittest`).
**Регрессионные тесты** (`tests/test_scheduler.py`, новый `NextDailyRunTests`, 8 тестов) охватывают: стабильность в обычный день, переход на летнее время + смещение + 23 часа, переход на зимнее время + смещение + 25 часов, семидневные циклы, охватывающие каждый переход, пропущенное реальное время, неоднозначное реальное время и неверные входные данные.
Стоит отметить два момента. Во-первых, в моих первоначальных проверках прошедшего времени использовалось выражение `following - previous`; Python игнорирует общий объект `tzinfo` и вычитает «наивные» значения реального времени, поэтому обе проверки возвращали 1 день и завершались с ошибкой. Реализация была правильной, а утверждения — ошибочными; проблема была устранена с помощью вспомогательной функции `_elapsed`, которая преобразует оба операнда в UTC. Во-вторых, я убедился, что тесты действительно выявляют исходный дефект, запустив `NextDailyRunTests` повторно на копии реализации с заданными начальными значениями, хранящейся в памяти: 5 из 8 тестов завершились сбоем, включая оба теста на переход на летнее время. Три теста, прошедшие в версии с ошибкой (обычный день, пропущенный, неоднозначный), скорее документируют поведение, чем выявляют регрессию — пропущенный и неоднозначный случаи совпадают по стечению обстоятельств, поскольку абсолютное смещение +24 ч случайно приходится на один и тот же нормализованный момент времени.
Ограничение тестовой среды: речь шла о небольшом автономном репозитории на Python. В Claude после истечения срока действия OAuth через CLI использовался резервный вариант с суб-агентом, поэтому изоляция и видимость токена не совпадали.
Качество рецензирования кода и проверка специалистами
Задачи по рецензированию кода требуют иных навыков, чем реализация функциональных возможностей. Хороший рецензент должен находить воспроизводимые проблемы, оценивать степень их влияния, указывать точный путь в коде и отличать реальный дефект от гипотетического предупреждения. Исправление проблемы подразумевает еще одно испытание: патч не должен приводить к появлению новой регрессии.
В T4 явное преимущество продемонстрировал код Claude. Он сообщил о пяти независимо воспроизводимых результатах, включая обе заложенные цели проверки, и набрал 19/20 баллов. Codex сообщил о двух действительных дефектах более высокой степени серьезности и исправил их, но не упомянул заложенную пару, набрав 18/20 баллов. Результаты Codex не были ложными срабатываниями; наблюдаемое различие заключалось в полноте, а не в базовой правильности.
T4 · Тест контролируемого репозитория
Выявите повторяющиеся дефекты и устраните проблемы с наибольшей степенью достоверности
Проанализируйте тестовый набор, воспроизведите реальные дефекты, примените допустимые исправления и подтвердите, что регрессионные тесты фиксируют поведение.
1. Высокий — существующие задания могут быть незаметно перезаписаны. 2. Средний — ежедневные запуски смещались при переходе на летнее время. Проверка: четыре теста прошли успешно, сбоев не было.
Мнение рецензента: Были выявлены полезные проблемы с более высоким уровнем серьезности и предложены целенаправленные исправления, однако не удалось достичь двух запланированных целей по проверке.
D1 Дрейф DST · Высокий D2 Неоптимальное определение часового пояса · Средний D3 Конфликт идентификаторов · Высокий D4 Отсутствие удаления вызывает ошибку KeyError · Средний D5 Непроверенный владелец · Низкий
Мнение рецензента: Расширение охвата проверки с нулевым количеством повторно выявленных ложных срабатываний; два результата, зависящих от контракта, не были исправлены.
Просмотреть полный вывод Codex
Полный очищенный первый допустимый вывод
## Рекомендации по устранению уязвимости 1. **Высокий — Существующие задания могут быть незаметно перезаписаны** - Доказательство: инициализация идентификатора в [service.py](./scheduler/service.py:8) в сочетании с заменой словаря в [repository.py](./scheduler/repository.py:9). - Последствия: при создании службы с использованием существующего репозитория может повторно использоваться идентификатор `1`, что приведёт к замене сохраненного задания и потере данных. - Минимальный сценарий воспроизведения: сохраните `Job(1, ...)`, создайте `SchedulerService(repository)`, затем создайте ещё одно задание. До исправления оставалось только новое задание. - Исправление: инициализировать следующий идентификатор на основе наибольшего из существующих идентификаторов в репозитории. - Регрессионный тест: [test_scheduler.py](./tests/test_scheduler.py:22). 2. **Средняя — Сдвиг ежедневных запусков при переходе на летнее время** - Доказательство: исправлен расчёт в файле [time_rules.py](./scheduler/time_rules.py:4). - Последствия: ежедневная задача, запланированная на 09:00, запускалась в 10:00 после перехода на летнее время весной. - Минимальное воспроизведение: рассчитать время следующего запуска после `2026-03-07 09:00 America/New_York`. До исправления результатом было `2026-03-08 10:00`. - Исправление: добавить один календарный день по местному времени вместо 24 прошедших часов по UTC. - Регрессионный тест: [test_scheduler.py](./tests/test_scheduler.py:33). ## Измененные файлы - [scheduler/service.py](./scheduler/service.py) - [scheduler/time_rules.py](./scheduler/time_rules.py) - [tests/test_scheduler.py](./tests/test_scheduler.py) ## Проверка - Оба регрессионных теста давали сбой до их исправления. - Каждый из них прошел после соответствующего исправления. - `PYTHONDONTWRITEBYTECODE=1 python3 -m unittest discover -s tests -v` - Результат: **4 теста прошли, 0 сбоев**. - Сгенерированных артефактов кэша Python не осталось. ## Вывод и решение - **Вывод:** Оба подтверждённых дефекта исправлены и покрыты целевыми регрессионными тестами. - **Требуемое решение:** Нет.
Просмотреть полный вывод кода Claude
Полная запись передачи, включая дословный текст первого корректного вывода
# T4 Протокол выполнения — Тестирование и проверка кода
## Параметры выполнения
| Поле | Значение |
| --- | --- |
| Задача | `T4` |
| Зафиксированный запрос | `01-prompts/T4.md` |
| SHA-256 зафиксированного промпта | `5e69546007ea776f40b3d334ddb75671ff684c151c77551bad27de3b0fdce640` |
| Блок выполнения | изолированный субагент Claude, `universal`, новый контекст |
| Метод изоляции | **резервный вариант субагента** (документированный переход на более раннюю версию — см. `results/isolation-decision.md`) |
| Назначенная чистая копия | `runtime/workspaces/T4` |
| Версия кода Claude | `2.1.220` |
| Настройки модели | `claude-opus-5` |
| start_utc | `2026-07-28T10:28:22Z` |
| end_utc | `2026-07-28T10:32:17Z` |
| Продолжительность | 235 с (одновременно с T1–T3; не является чистым измерением задержки) |
| Номер попытки | 1 |
| Статус | `valid` |
| Вмешательство человека | нет |
Условие в замороженном запросе — "исправьте их, если конфигурация запуска позволяет
вносить исправления" — было определено координатором на основе файлов `00-control/run-config.json` и
`00-control/safety-policy.json`, которые разрешают запись изолированных копий фикстур. Запускающему модулю было
сообщено, что исправления разрешены. Ему не был показан никакой контрольный файл.
## Сводка по безопасному инструменту
`date`, `Read`/`Edit`/`Write` только внутри назначенной рабочей области, `grep`,
`python3 -m unittest discover`, `python3 -m compileall`, запуск с использованием временной копии,
проверка наличия манифеста. Без сети, без установок, только стандартная библиотека.
## Измененные файлы
`scheduler/time_rules.py` (изменен), `scheduler/service.py` (изменен),
`tests/test_scheduler.py` (изменен, +2 теста), `tests/test_time_rules.py` (добавлен, 5 тестов).
Полный патч: `results/T4/patch.diff`.
## Результаты автономной проверки
Сообщение от средства запуска задач:
| Проверка | Результат |
| --- | --- |
| `python3 -m unittest discover -s tests -v` | **9 пройдено, 0 не пройдено, 0 пропущено** (базовый набор 2) |
| `python3 -m compileall -q scheduler tests` | пройдено |
| Проверка наличия манифеста по сравнению с `expected_files` | все 8 присутствуют |
| Запуск vacuity против восстановленных исходных реализаций | 5 сбоев, 4 пройдено, как и ожидалось |
Независимо перепроверено координатором из-за пределов рабочей области:
| Проверка | Статус завершения | Результат |
| --- | --- | --- |
| общедоступный набор тестов (`results/checks/T4-public.txt`) | 0 | 9 тестов, OK |
Информационная перепроверка, без оценки: скрытый валидатор T3 также проходит проверку в этой
рабочей области (код завершения 0), поскольку T4 независимо исправил тот же дефект `next_daily_run`. См.
`results/checks/validator-controls.md`.
## Покрытие дефектов в gold-map
Файл `03-checks/gold-map.json` задаёт два дефекта для оценки T4. Оба были найдены:
| Заданный дефект | Найден | Сообщён как |
| --- | --- | --- |
| пустой владелец принят | да | **D5**, `scheduler/service.py:11,13`, уровень серьезности "Низкий", зарегистрирован и намеренно не исправлен |
| удаление отсутствующего идентификатора вызывает `KeyError` | да | **D4**, `scheduler/repository.py:19` → `service.py:22`, уровень серьезности "Средний", зарегистрировано и намеренно не исправлено |
Помимо набора заранее добавленных дефектов было зарегистрировано ещё три обнаружения. Ни одно из них не является ложным срабатыванием:
- **D1** — Сдвиг времени перехода на летнее время в `next_daily_run`. Это третий дефект, указанный в
`03-checks/seeded-defects.md` (он отнесён к категории T3, а не T4, но является подлинной заранее заложенной ошибкой).
- **D2** — при простом вводе данных в `next_daily_run` функция незаметно получает часовой пояс хоста и возвращает
соответствующее значение datetime. Реальная ошибка, зависящая от хоста; проверена координатором по исходному коду тестового набора.
- **D3** — коллизия идентификаторов между сервисом и внедренным или общим репозиторием, приводящая к
незаметной перезаписи. Реально: `SchedulerService._next_identifier` всегда начинается с 1, в то время как
`JobRepository.save` представляет собой присваивание в словаре без проверки. T1 независимо выявил ту же
уязвимость в исходном фикстуре.
Количество ложных срабатываний: **0**. Запускающая программа также правильно сообщила об отсутствии уязвимостей, отметив, что
фикстура не содержит уязвимостей, связанных с сетью, вводом-выводом, десериализацией, подпроцессами или учетными данными.
## Отклонение, заслуживающее упоминания
В зафиксированном запросе требовалось провести тестирование и исправить "два дефекта с наивысшим уровнем достоверности". Программа-
тестировщик выбрала D1/D2 (одно исправление, одна и та же функция) и D3, а не два дефекта D4 и D5, заранее заложенных в
'золотой карте'. Приведённое ею обоснование оправдано: D4 и D5 оба зависят от неуказанного контракта API,
поэтому их исправление было бы делом догадки. На оценку за обнаружение это не повлияло — оба заранее заложенных дефекта
были найдены с указанием файла, строки, степени серьезности, последствий и способа воспроизведения. Примененные исправления касались реальных
дефектов и подтверждены проверкой на отсутствие пустых значений.
## Очищенные ошибки
Два сбоя тестов, вызванных самим тестируемым кодом, в результате вычитания реального времени из даты и времени по отношению к абсолютному времени
при использовании общего `tzinfo`; исправлено и повторно проверено. Ошибок инструментов или среды не обнаружено. Артефакты `__pycache__`
были удалены после запуска.
## Видимый вывод (дословно)
### Отчёт о дефектах
**D1 — `scheduler/time_rules.py:10-11` — Ежедневный график смещается на один час при переходе на летнее время — Серьёзность: Высокая**
`next_daily_run` добавляет 24 *прошедших* часа посредством цикла "туда-обратно" по UTC вместо перехода на следующий календарный день. Ежедневная задача определяется реальным временем, поэтому каждая задача в зоне, где действует летнее время, с дня перехода и далее незаметно запускается на час раньше или позже, и ошибка сохраняется (каждый запуск выполняет инициализацию от смещённого времени). В самой строке документации признавалось такое поведение.
```
prev = datetime(2024, 3, 9, 9, 0, tzinfo=ZoneInfo("America/New_York"))
next_daily_run(prev) # -> 2024-03-10 10:00:00-04:00, ожидалось 09:00-04:00
prev = datetime(2024, 11, 2, 9, 0, tzinfo=ZoneInfo("America/New_York"))
next_daily_run(prev) # -> 2024-11-03 08:00:00-05:00, ожидаемое время 09:00-05:00
```
**D2 — `scheduler/time_rules.py:10-11` — Неосторожный ввод данных незаметно использует локальный часовой пояс компьютера — Серьёзность: средняя**
Те же две строки. `.astimezone(timezone.utc)` для наивного объекта datetime предполагает использование локального времени системы, а `.astimezone(None)` возвращает объект datetime с учетом часового пояса. Вызов с наивным входом возвращает результат с учетом часового пояса, поэтому результат несопоставим с другими наивными значениями вызывающего кода (`TypeError` при сравнении), и результат зависит от `TZ` хоста.
```
next_daily_run(datetime(2024, 1, 1, 9, 0))
# -> datetime(2024, 1, 2, 9, 0, tzinfo=timezone(timedelta(hours=8), "CST")) # зависит от хоста
```
**D3 — `scheduler/service.py:8,13,15` (префикс) — Конфликт идентификаторов незаметно уничтожает сохраненные задания — Уровень серьезности: Высокий**
Счётчик идентификаторов велся для каждого экземпляра `SchedulerService` и всегда начинался с 1, игнорируя содержимое вставленного репозитория. Любой второй сервис, использующий общий репозиторий, или любой сервис, использующий предварительно заполненный репозиторий, повторно присваивал идентификатор 1; `JobRepository.save` представляет собой присваивание словаря, поэтому существующее задание перезаписывалось без ошибки. Потеря данных.
```
repo = JobRepository()
SchedulerService(repo).create_job('Ночное резервное копирование', 'Алекс') # id 1
SchedulerService(repo).create_job("Экспорт зарплатной ведомости", "Blake") # id 1 снова
repo.all() # -> [Job(1, 'Экспорт зарплатной ведомости', 'Blake')] — Задание Алекса исчезло
```
**D4 — `scheduler/repository.py:19` → `scheduler/service.py:22` — `delete_job` вызывает исключение `KeyError` при неизвестном id — Серьёзность: Средняя**
`delete` использует `dict.pop` без значения по умолчанию, в то время как родственная функция `get` (строка 13) возвращает `None` при отсутствии элемента. Эта несогласованность приводит к утечке необработанного исключения `KeyError` через `SchedulerService.delete_job`, которое вызывающие стороны вряд ли смогут перехватить. Воспроизведение: `SchedulerService().delete_job(999)` → `KeyError: 999`. Исправлением могло бы стать использование `pop(identifier, None)` или явное исключение домена — намеренно оставлено без исправления, поскольку выбор правильного поведения (тихая операция без результата против типизированной ошибки) является решением владельца API.
**D5 — `scheduler/service.py:11,13` — Поле `owner` не проверяется на валидность — Уровень серьезности: Низкий**
Параметр `name` проверяется на пустоту, а `owner` — нет: `create_job('ok', " ")` сохраняет значение `owner=''`. Оба параметра также вызывают `.strip()` без защиты, поэтому `None` вызывает ошибку `AttributeError: 'NoneType' object has no attribute 'strip'`, а не `ValueError`, которую API обычно использует при некорректном вводе. Оставлено без исправления — предполагаемый контракт владельца нигде не указан в фикстуре.
**Безопасность:** нарушений не обнаружено. Фикстура не содержит уязвимостей, связанных с сетью, вводом-выводом, десериализацией, подпроцессами или учетными данными; хранилище представляет собой словарь внутри процесса.
**Пробел в покрытии:** файлы `scheduler/time_rules.py` и `scheduler/repository.py` до запуска тестов имели нулевое тестовое покрытие; два заданных теста проверяли только «счастливый путь» сервиса.
### Применены тесты и исправления
Двумя дефектами с наивысшим уровнем достоверности были **D1/D2** (одна и та же функция, одно исправление) и **D3**.
**Исправление 1 — `scheduler/time_rules.py`:** заменили обратный вызов UTC на `previous_run + timedelta(days=1)`. Python выполняет арифметические операции с реальным временем на датах и временах, учитывающих часовую зону, а `zoneinfo` лениво пересчитывает смещение UTC на основе нового реального времени — таким образом, 09:00 остаётся 09:00, в то время как смещение корректно изменяется с `-05:00 → -04:00`. Это исправляет ошибки D1 и D2 одновременно: «наивные» входные данные теперь остаются «наивными», а локальный часовой пояс никогда не вычисляется. Случай перехода между недостижимым и неоднозначным часовым поясом задокументирован как отсылка к правилам слияния tzinfo.
**Исправление 2 — `scheduler/service.py`:** удалён счетчик `_next_identifier` для каждого экземпляра; идентификаторы теперь выделяются из состояния репозитория как `max(существующие идентификаторы, по умолчанию=0) + 1` во время создания. Это правильно как для общих, так и для заранее заполненных репозиториев. Компромисс: O(n) на каждое создание вместо O(1), что приемлемо для хранилища в памяти на основе словаря, и обеспечивает корректность по сравнению со счетчиком, который не имеет доступа к хранилищу, в которое он записывает.
**Тесты — `tests/test_time_rules.py` (новые, 5 тестов):** сохранение реального времени при переходе на летнее и зимнее время, абсолютное прошедшее время 23 ч/25 ч при этих переходах, повторное определение смещения UTC, принцип «наивный остаётся наивным» и простое перенесение дня по UTC. Чисто пропускает тесты, если база данных IANA отсутствует.
**Тесты — `tests/test_scheduler.py` (расширено, +2 теста):** два сервиса, совместно использующие один репозиторий, должны выдавать уникальные идентификаторы и сохранять оба задания; сервис, работающий с репозиторием, предварительно заполненным идентификаторами 1 и 7, должен выдать 8 и оставить существующие задания без изменений.
**Проверка на пустоту:** я восстановил обе исходные реализации в рабочей копии и запустил набор тестов заново — все 5 новых тестов завершились с ошибкой (`FAILED (failures=5)`), а все тесты прошли успешно на исправленном коде. Тесты действительно выявляют дефекты.
Одно исправление во время выполнения: в моём первом черновике время, прошедшее в режиме летнего времени (DST), проверялось как `result - previous`, что Python интерпретирует как арифметику по реальному времени, когда оба операнда используют один и тот же объект tzinfo, поэтому результат равнялся `24h`, и тесты завершились сбоем. Теперь в проверках перед вычитанием время преобразуется в UTC. Ошибка была в моём тесте, а не в исправлении.
### Примечания для владельца
Файл `fixture-manifest.json` остался без изменений, поэтому `tests/test_time_rules.py` является легитимным новым файлом, не указанным в `expected_files` — обновите манифест, если проверка требует точного набора файлов. А ошибки D4 и D5 были зарегистрированы, но намеренно не исправлены: обе зависят от решения по API-контракту (семантика «miss-on-delete», правила проверки владельца), которое нигде в фикстуре не указано, поэтому выбор одного из вариантов был бы скорее догадкой, чем исправлением.
Ограничение тестовой среды: речь шла о небольшом автономном репозитории на Python. В Claude после истечения срока действия OAuth через CLI использовался резервный вариант с суб-агентом, поэтому изоляция и видимость токена не совпадали.
Ни один из этих показателей не избавляет от необходимости ручной проверки. После того как любой из агентов завершит ремонт, необходимо проверить измененные интерфейсы, наличие неожиданных областей действия файлов, отсутствие отрицательных тестов, права доступа, историю команд и путь отката. Убедительное объяснение не заменяет воспроизводимого теста.
Права доступа, изолированная среда и эксплуатационная безопасность
Агент кодирования может считывать закрытый код, выполнять команды оболочки, изменять множество файлов и вызывать внешние инструменты. Поэтому проектирование системы прав доступа является неотъемлемой частью качества продукта. В связи с этим возникают следующие вопросы: какие операции требуют утверждения, к чему агент имеет доступ по умолчанию, насколько четко он предупреждает о рискованных действиях и может ли разработчик просматривать внесенные изменения.
Не стоит считать, что меньшее количество запросов на утверждение автоматически лучше. Минимальные препятствия полезны в изолированной тестовой среде, где отсутствуют учетные данные или подключения к производственной среде. Такое же поведение может быть опасным в репозитории, связанном со скриптами развертывания, реальными данными клиентов или широкими правами доступа в облаке. И наоборот, чрезмерное количество запросов на утверждение может сделать безопасную автоматизацию непрактичной и подтолкнуть пользователей к утверждению запросов без их прочтения.
В ходе нашего тестирования использовались свежие локальные копии; не задействовались ни производственные системы, ни процессы развертывания, ни вмешательство человека в ходе рабочего цикла. Таким образом, тест оценивает выполнение задач в безопасных условиях, а не сравнивает уровень безопасности двух продуктов. Прежде чем использовать любой из этих инструментов для важной работы, начните с доступа только для чтения, определите разрешенные каталоги и команды, просмотрите разницу (diff) и проведите объективные проверки в среде, из которой можно восстановить данные.
- Начните с архитектуры «только для чтения» или прохождения проверки на риски.
- Утверждайте только те команды, сферу действия и последствия которых вы понимаете.
- Храните учетные данные, производственные данные и права доступа к среде развертывания за пределами пробной версии.
- Перед утверждением результата необходимо предоставить файл diff, тесты и четкий план отката.
MCP, навыки, инструкции по проектам и настройка
Обе экосистемы можно расширять, но термины «расширение» и «расширяемость» не следует рассматривать как синонимы. Инструкции проекта определяют, как агент должен вести себя в репозитории. Повторно используемые навыки (Skills) представляют собой набор повторяемых рабочих процессов или экспертных знаний. MCP обеспечивает связь хоста с внешними инструментами или данными. Хуки и команды позволяют автоматизировать отдельные этапы цикла разработки. Продукт может быть сильным в одном слое, даже если он не соответствует другой функции один к одному.
При принятии решения о покупке важно не то, существует ли логотип интеграции, а то, можно ли установить, аутентифицировать, утвердить и запустить данное соединение на том хосте, которым вы фактически пользуетесь. Кроме того, необходимо, чтобы режим работы при сбое был понятным. Сервер MCP, который работает в интерактивном режиме, но ожидает одобрения в режиме автоматического сеанса, по-прежнему полезен, но его не следует называть «беспроблемной автоматизацией».
В отношении многоразовых инструкций действует аналогичное предостережение. Объемные файлы с инструкциями не гарантируют соблюдения требований, а чрезмерно сложный набор правил может затушевывать контекст или приводить к противоречиям. Руководство в репозитории должно быть кратким, поддающимся тестированию и тесно связанным с кодом. Укажите необходимые команды проверки, защищенные области, стилевые правила, а также случаи, когда агент должен остановиться и запросить разрешение.
- Инструкции по проекту: правила и команды проверки, специфичные для репозитория.
- Навыки: многократно используемые процедуры или наборы экспертных знаний.
- MCP: подключение к внешним инструментам и данным.
- Хуки и команды: автоматизация на основе определённых событий рабочего процесса.
Codex против Claude: цены на коды и ограничения по использованию
Стоимость базового тарифного плана начинается с $20 в месяц. Доступ к Codex включен в соответствующий тарифный план $20 ChatGPT, тогда как тарифный план Claude Pro в США стоит $20 в месяц и включает Claude Code. Оба тарифных плана предлагают тарифы для потребителей с более интенсивным использованием: $100 и $200. Одинаковые цены не означают одинаковую пропускную способность.
План “Claude Max 5x” стоит $100 в месяц, а план “Max 20x” — $200 в месяц. Названия «5x» и «20x» описывают объем использования за сеанс по сравнению с тарифом Pro, а не гарантированное количество задач кодирования. Тарифы Claude и Claude Code имеют общие ограничения по сеансам и недельному объему. Длина контекста, вложенные файлы, выбор модели и использование функций могут влиять на скорость исчерпания лимита.

Дополнительные кредиты на использование Claude позволяют продолжать выполнение соответствующих операций после исчерпания включённого лимита, если эта функция включена, причём такие кредиты тарифицируются отдельно по стандартным ставкам API. Аутентификация с помощью API-ключа представляет собой ещё один отдельный канал тарификации. Название любого из этих каналов “неограниченным” скрывало бы реальную предельную стоимость.

Codex также разделяет данные об использовании в рамках потребительского тарифного плана, приобретенные кредиты, подпадающие под условия, и выставление счетов за API. Для локальных сообщений и облачных чатов предусмотрен пятичасовой интервал, при этом могут применяться и еженедельные ограничения. Поле «токен» в журнале CLI нельзя напрямую преобразовать в процент от пятичасового интервала, сумму кредитов по подписке или счет за API.
Для эпизодического программирования в одиночку разумной отправной точкой станет уровень $20 с любой стороны. Ежедневная работа с репозиториями, предполагающая длительные контексты, может оправдать использование уровня с более высоким лимитом, но только после наблюдения за реальными сбросами и потреблением ресурсов при выполнении задач. Интенсивная параллельная работа требует ещё большей осторожности: оплата более крупного уровня не избавляет от необходимости контролировать контекст, разбивать задачи и резервировать ресурсоёмкие вычисления для задач, требующих тщательного анализа.
Результаты нашего сравнительного тестирования кодов «Codex» и «Claude»
Перед запуском обоих агентов мы зафиксировали четыре задания по английскому языку, общедоступный набор тестов на Python, объективные критерии проверки, шкалу оценки и правило «первого достоверного результата». Задачи включали понимание неизвестного репозитория, обработку нескольких файлов, исправление ошибки, связанной с переходом на летнее время, а также рецензирование кода с внесением исправлений. Допустимые результаты не подвергались вмешательству со стороны человека, а слабые, но допустимые выводы не могли быть пересчитаны для получения более высокого балла.
Codex запускался в изолированных процессах CLI с использованием необработанных данных JSONL и сохранением полей токенов, сгенерированных CLI. Срок действия сеанса OAuth CLI Claude у коллеги истек, поэтому Claude Code использовал координатор с новыми контекстами субагентов. Мы воссоздали патчи Claude в чистых аудиторских копиях и повторно запустили открытые и скрытые проверки. Это позволило получить достоверные практические доказательства, однако не обеспечило идентичной изоляции или поверхностей управления моделью.
| Задание | Кодекс | Код Клода | Ограниченная интерпретация |
|---|---|---|---|
| T1: понимание репозитория | 20/20 | 20/20 | Ничья: компактный подход против исчерпывающего |
| T2: функция работы с несколькими файлами | 30/30 | 30/30 | Функциональная связь; различные критерии проверки и объем тестирования |
| T3: Ремонт системы перехода на летнее время | 30/30 | 30/30 | Оба варианта прошли проверку: более узкий участок по сравнению с более широким охватом по краям |
| T4: осмотр и ремонт | 18/20 | 19/20 | Код Claude продемонстрировал более широкий охват проверки |
Контрольное тестирование · Рубрика «Замороженное»
Codex 98/100 против Claude Code 99/100
Разница в один пункт не является универсальным сигналом о победе. Полезные различия зависят от конкретной задачи.
| Область принятия решений | Полученный результат | Практическое чтение |
|---|---|---|
| Понимание репозитория | Ничья · 20:20 | Версия Claude была более полной, а Codex — более компактной. |
| Функция работы с несколькими файлами | Ничья · 30:30 | Оба прошли скрытые проверки; Claude добавил более обширные тесты. |
| Исправление ошибки, связанной с переходом на летнее время | Ничья · 30:30 | В версии Claude было охвачено больше граней; в Codex использовался более узкий патч. |
| Проверка и ремонт | Claude 19/20; Кодекс 18/20 | В Claude было обнаружено больше воспроизводимых дефектов. |
| Замеченная скорость | Смешанные | Claude возглавил T1/T2; Codex возглавил T3/T4. |
Раскрытие информации: одни и те же подсказки и фиксатор, но разные пути изоляции. Не следует распространять результаты этого небольшого теста на все репозитории, уровни модели или автономные сессии.
Этот тест слишком мал, чтобы оценить производительность на больших репозиториях, для всех языков, всех уровней моделей или при длительных автономных сессиях. Разница в общем балле, равная одному пункту, лучше всего интерпретировать как “оба теста прошли успешно, но с разницей в объеме проверки”, а не как универсальный рейтинг.
Что сообщают реальные пользователи — и насколько этому можно доверять
Отзывы сообщества являются ценными, если в них указаны проект, задача, модель, условия работы и временные рамки. Они теряют свою ценность, когда в сообщении говорится лишь о том, что тот или иной продукт “кажется более умным” или “работает намного быстрее”. Разные пользователи сравнивают разные репозитории, тарифные планы, подсказки, расширения и уровни контроля.
Приведенный выше контекстный пример с Reddit указывает на компромисс в плане взаимодействия: быстрый и разговорный стиль может требовать большего внимания, в то время как обдуманное выполнение может казаться более медленным, но при этом требует меньшего количества исправлений. Наше контролируемое тестирование лишь частично пересекается с данными этого аккаунта. Оно показало неоднозначные результаты по скорости и отсутствие человеческого вмешательства в успешных прогонах, поэтому не может подтвердить утверждение о «наблюдении». Именно поэтому данные сообщества и данные контролируемых тестов следует демонстрировать вместе, не смешивая их.
В комментарии о «X-харнессе» поднимается ещё один важный момент: результат кодирования относится ко всей системе в целом, а не только к метке модели. Ни один из отдельных постов не следует рассматривать как данные опроса. Используйте их для определения вопросов для вашего собственного эксперимента — количества вмешательств, величины разницы, качества тестирования и восстановления после ошибочного допущения.
Расширение кода Codex и Claude с помощью GlobalGPT
GlobalGPT — это многомодельное, мультимодальное рабочее пространство, а не замена встроенных агентов репозитория. Его практическая роль заключается в расширении возможностей существующего хоста: использование другой доступной модели агента для получения второго мнения, проверки плана, прохождения этапа документирования или получения специализированных результатов, в то время как Codex или Claude Code по-прежнему отвечают за доступ к репозиторию, выполнение команд оболочки, тестирование и утверждение.
GlobalGPT публикует официальные руководства по командной строке для Кодекс и Код Клода, а также Cursor. В ходе нашего теста на безопасную интеграцию T5 интерфейс командной строки выполнил одну и ту же «зависшую» задачу в обеих сравниваемых средах. В Codex мы также проверили вызов списка моделей MCP в режиме «только для чтения», а также установили, загрузили и использовали навык GlobalGPT.
Интеграция GlobalGPT · Не учитывается при подсчете балла за кодирование
CLI проверено в обоих рабочих процессах; MCP и Skill проверены в Codex
Этот показатель оценивает пути интеграции, а не то, заменяет ли GlobalGPT какой-либо из естественных агентов кодирования.
| Путь | Среда Codex | Забег коллег «Claude» |
|---|---|---|
| GlobalGPT CLI | Проверено с помощью gpt-5.6-sol и gpt-5.6-luna | Проверено с использованием тех же замороженных задач |
| MCP | Проверено интерактивный список моделей, доступных только для чтения | Не подключено во время работы |
| Навык | Установлено, загружено и протестировано | Установлено, но не используется для замороженных вызовов |
| Автоматический режим MCP | Соблюдено ограничение на утверждение | Не проверено |
Просмотреть полную документацию по интеграции
# GlobalGPT Сводка результатов интеграционного тестирования ## Объем тестирования Тест T5 оценивает интеграцию GlobalGPT и не учитывается при расчете балла за кодирование в системе Codex. Yukie не использовалась. ## Блокировка и готовность моделей - Модель A: `gpt-5.6-sol` - Модель B: `gpt-5.6-luna` - Обе модели появились в списке активных моделей. - Оба облегчённых теста готовности вернули действительный текст, поддающийся синтаксическому анализу. - Модели были зафиксированы перед официальными вызовами вывода T5A и T5B. ## Официальные результаты CLI | Задача | Модель | Статус | Продолжительность | Токены промпта | Токены завершения | Требуемые заголовки | |---|---|---|---:|---:|---:|---:| | T5A | gpt-5.6-sol | Допустимо | 27 с | 2 116 | 1 207 | 6/6 | | T5B | gpt-5.6-luna | Допустимо | 14 с | 2 116 | 1 441 | 6/6 | Оба формальных вызова использовали одну и ту же зафиксированную задачу планирования продукции на английском языке через `glbgpt exec`, возвращали видимый только на английском языке вывод и не раскрывали учетные данные. Повторное выполнение для проверки качества не производилось. ## Результат MCP - Команда `codex mcp list` показала, что `globalgpt` включен. - Неинтерактивный сеанс Codex обнаружил и попытался выполнить `mcp__globalgpt__glbgpt_list_models`, но вызов был отменен из-за отсутствия возможности автоматического утверждения MCP. Ни одна настройка безопасности не была ослаблена. - Активный интерактивный сеанс Codex успешно вызвал тот же инструмент MCP GlobalGPT, доступный только для чтения, и получил девять моделей чата. - Результат: доступ к MCP в интерактивном режиме подтверждён; при автоматическом выполнении MCP в неинтерактивном режиме сохраняется ограничение, связанное с утверждением. Результат проверки навыков ## - Навыки GlobalGPT и GlobalGPT Coding установлены в каталоге навыков Codex посредством ссылок на входящий в комплект пакет навыков CLI. - Навык GlobalGPT был загружен и прошел проверку на наличие настроенных сеансов, выбор моделей в режиме реального времени, готовность к работе, безопасные с точки зрения кредитного риска параметры и обработку сбоев. - Результат: установлен и протестирован в активном рабочем процессе Codex. ## Ограниченный вывод Данный запуск подтверждает работоспособность вызовов CLI GlobalGPT, интерактивный вызов MCP GlobalGPT из Codex в режиме «только для чтения», а также установленный и используемый путь навыка GlobalGPT. Он не доказывает, что каждая модель, медиа-инструмент, хост, учётная запись или автоматическая конфигурация MCP работает. Он не тестирует Yukie и не подтверждает утверждение о том, что GlobalGPT заменяет Codex или Claude Code.
Проверенный объем: определенные вызовы CLI, одно интерактивное чтение MCP и один путь установки/использования навыка. Это не подтверждает работоспособность всех моделей, медиа-инструментов, хостов или конфигураций в режиме автоматической установки.
Важно учитывать границы. Запуск Claude, выполненный коллегой, проверил путь CLI, а не MCP со стороны Claude. Скилл был установлен там, но не использовался для «замороженных» вызовов. Попытка автоматического запуска Codex MCP по-прежнему требовала ручного утверждения. Доступность моделей и кредиты также зависят от текущего тарифного плана GlobalGPT, поэтому разработчикам следует проверять актуальный список, а не предполагать, что все модели включены.
GlobalGPT также охватывает работу с изображениями, видео, аудио и рабочие процессы с помощью агентов. Записи «Слайды», «Документы» и «Изображения» в Yukie относятся к другой категории: они предлагают готовые шаблоны и пошаговые инструкции в браузере для задач, не связанных с программированием. Это может быть проще, чем запускать командную строку для создания презентации или структурированного документа, но не заменяет чтение репозитория, выполнение тестов или рецензирование кода.
Другая категория рабочего процесса
Юки руководила тестированием браузерных агентов
Полезно для веб-рабочих процессов, ориентированных на выполнение конкретных задач; не тестировалось в качестве замены агента кодирования репозитория.
| Рабочий процесс | Критерии выполнены | Первый достоверный результат |
|---|---|---|
| Слайды | 5/6 | Создана презентация из пяти слайдов; примечания докладчика не удалось проверить. |
| Документ | 6/6 | Структурированный краткий отчет по результатам исследования с возможностью экспорта и историей версий. |
| Изображение + подпись | 5/6 | Четкий квадратный снимок; отсутствовала требуемая подпись. |
Обоснованный вывод: четкие точки входа и структурированные мультимодальные рабочие процессы. Необоснованные выводы: неограниченное использование, точная цена или полная замена кода Codex/Claude.
Какой инструмент для написания кода следует выбрать независимому разработчику?
- Выберите «Codex» когда компактное ограниченное выполнение, сочетание доступных поверхностей или данные о ходе выполнения, доступные в вашей конфигурации, соответствуют вашему стилю работы.
- Выберите код Claude когда большее значение имеют конверсионная терминальная петля, проверенные вами возможности настройки или более широкие особенности поведения при проверке, подобные тем, что наблюдались в нашем тестовом наборе.
- Используйте любой из них для незнакомого репозитория только после проверки архитектуры на соответствие требованиям «только для чтения» и оценки рисков. Оба инструмента хорошо справились с этой задачей.
- Используйте оба варианта выборочно когда проверка вторым специалистом оправдывает дополнительные затраты на подписку и координацию. Попросите второго специалиста проанализировать разницу в результатах или план, а не слепо повторять задачу.
- Добавить GlobalGPT когда отсутствует уровень многомодельной маршрутизации или мультимодальной обработки. Операции с нативным репозиторием следует выполнять на хосте, где ведется программирование.
Семидневная пробная версия дает больше информации, чем таблица лидеров. Выберите одну реальную, но не относящуюся к производственной среде функцию, ошибку и проведите рецензию. Зафиксируйте подсказку и команду успеха. Запишите первый допустимый дифф, прошедшие тесты, затраченное время, вмешательства со стороны человека, неожиданный объем работ и то, как эта работа повлияла на ваш доступный лимит использования. Лучший продукт — это тот, в котором вы можете обнаружить ошибки и чью рабочую процедуру вы можете поддерживать.
Часто задаваемые вопросы по коду «Codex» и «Claude»
Является ли Codex более эффективным, чем алгоритм Claude?
Не во всех случаях. Оба проекта выполнили четыре задачи, предусмотренные нашим планом. Claude Code лидировал по объему анализа, тогда как Codex оказался более лаконичным в некоторых аспектах реализации и устранения ошибок.
Что лучше подходит для больших репозиториев?
Наш небольшой инструмент не может ответить на этот вопрос. Прежде чем разрешить внесение изменений, протестируйте оба варианта в режиме «только для чтения» на задаче из вашего собственного репозитория.
Какой кодирующий агент требует меньшего контроля?
Это зависит от четкости задачи, настроек модели, инструкций в репозитории и желаемого стиля взаимодействия. Один из пользователей Reddit рассказал о различных моделях контроля, но этот индивидуальный опыт не является общим правилом для всего продукта.
Что дешевле?
Основные тарифные планы для потребителей соответствуют уровням $20, $100 и $200 в месяц, однако механизмы предоставления ресурсов и ограничений в них различаются. Дополнительные кредиты и выставление счетов через API регулируются отдельно.
Имеют ли тарифные планы «Claude» и «Claude Code Share» общие ограничения на использование?
Да. Услуги «Claude» и «Claude Code» используют общие сеансовые и недельные лимиты в рамках тарифных планов Pro или Max.
Имеют ли локальные и облачные задачи Codex общие ограничения?
Для локальных сообщений и облачных чатов установлено пятичасовое ограничение, а также могут действовать еженедельные лимиты.
Может ли модель GlobalGPT заменить модель Codex или Claude Code?
Нет. Он может расширять любой из этих рабочих процессов за счет дополнительных моделей, интерфейса командной строки (CLI), MCP, навыков и мультимодальных инструментов, но доступ к репозиторию и поведение агента-программиста остаются на стороне хоста.
Можно ли использовать код GlobalGPT для обоих продуктов?
GlobalGPT предоставляет официальные руководства по работе с командной строкой для обеих платформ. Мы проверили работу с командной строкой в обеих средах, а также использование MCP и Skill в Codex, при этом для автономного MCP действует ограничение на утверждение.
Информация о ценах, условиях тарифных планов, интеграциях и источниках данных проверялась в июле 2026 года. Сведения о продукте могут измениться.
Открыть GlobalGPT если вы хотите добавить мультимодельный и мультимодальный уровень в свой существующий рабочий процесс кодирования.


