Добавляет разовый импортер Статьи.csv: по умолчанию read-only dry-run, применение одной транзакцией, сопоставление только с существующими сотрудниками, заполнение пустых полей и отдельные CSV-метаданные, отчёт insert/update/skip. Нет удаления данных или изменений схемы.
Crawler ранее удалял CSV-вставки при непустом ответе ВШЭ и стирал метаданные при обновлении найденных статей. Теперь сохраняет записи и csv_enrichment, использует импортированную запись при последующем появлении статьи у ВШЭ и откатывает синхронизацию при неоднозначности. Обычная очистка устаревших HSE-записей сохранена.
Документация: docs/publication-import.md — затронутые столбцы и sequence, минимальные grants, временная роль, ограниченные SSH-команды и отзыв доступа. Версия 0.10.1.
Проверки: 69 локальных тестов, включая повторный crawl после применения плана импорта, отсутствие дубликатов и rollback при неоднозначном соответствии; shell syntax и git diff --check. Это SQLite и тестовые соединения, не проверка настоящего PostgreSQL. Production, роли БД и работа crawler не менялись. Требуется независимое ревью перед дальнейшими действиями.
Добавляет разовый импортер Статьи.csv: по умолчанию read-only dry-run, применение одной транзакцией, сопоставление только с существующими сотрудниками, заполнение пустых полей и отдельные CSV-метаданные, отчёт insert/update/skip. Нет удаления данных или изменений схемы.
Crawler ранее удалял CSV-вставки при непустом ответе ВШЭ и стирал метаданные при обновлении найденных статей. Теперь сохраняет записи и csv_enrichment, использует импортированную запись при последующем появлении статьи у ВШЭ и откатывает синхронизацию при неоднозначности. Обычная очистка устаревших HSE-записей сохранена.
Документация: docs/publication-import.md — затронутые столбцы и sequence, минимальные grants, временная роль, ограниченные SSH-команды и отзыв доступа. Версия 0.10.1.
Проверки: 69 локальных тестов, включая повторный crawl после применения плана импорта, отсутствие дубликатов и rollback при неоднозначном соответствии; shell syntax и git diff --check. Это SQLite и тестовые соединения, не проверка настоящего PostgreSQL. Production, роли БД и работа crawler не менялись. Требуется независимое ревью перед дальнейшими действиями.
Origin сверён с clone_url репозитория PR. Через GET /repos/admin/miem_workers/pulls/54 подтверждён автор codex (id 6), через GET /user — reviewer agent (id 7); идентичности разные. Перед публикацией head повторно проверен, изменений нет.
Проверен полный diff всех 11 файлов и окружающий поток: parser → _upsert_employee → savepoint публикаций → сопоставление/обновление/очистка; модель, SQL миграция, импортер, тесты, инструкции grants, SSH wrappers и отзыв доступа.
Замечания, препятствующие approval:
[P1] Crawler может сопоставить одну CSV-запись с несколькими разными HSE publication_id и молча потерять первую статью. imported включает также уже привязанные и ранее обогащённые HSE-записи. Для одной CSV-статьи Same/2024 без DOI и двух входящих статей hse-A и hse-B с этим названием/годом оба вызова _match_imported_publication возвращают тот же id. После двух _apply_publication остаются только publication_id=hse-B, его authors и raw_data; данные hse-A перезаписаны без ValueError/rollback. Parser сохраняет разные HSE id, поэтому они действительно могут попасть в один обход. Необходимо контролировать соответствие в обе стороны и конфликт уже установленного HSE id; неоднозначность должна откатывать savepoint, а не зависеть от порядка статей. Нужен регрессионный тест двух HSE id на одну CSV-запись, включая уже привязанную запись.
[P2] Apply предполагает наличие raw_data во всех действиях, хотя plan удаляет неизменённые поля. Если csv_enrichment уже содержит исходную строку, а канонический year пуст, plan корректно возвращает update с values={year: 2024}. Строка 158 затем вызывает KeyError на values[raw_data]. Dry-run такого плана успешен, apply откатывает весь импорт. Jsonb нужно применять только при наличии raw_data; проверить настоящий путь apply для обновления одного канонического поля без изменения JSON.
[P2] Ранний csv_duplicate отбрасывает поздние непустые метаданные. Для двух строк с одинаковыми сотрудником/DOI, где первая без Scopus/квартиля, а вторая содержит Scopus=new-id и квартиль=Q1, остаётся одна вставка, но оба дополнительных значения отсутствуют. Повторный импорт в том же порядке также их не добавит. Это нарушает описанный приоритет первого непустого значения и сохранение исходных CSV-метаданных. Нужно дополнять пустые метаданные у повторов, сохраняя уже заполненные значения и одну публикацию.
Проверки: воспроизведения выполнены на функциях именно этого head в памяти со стандартной библиотекой и синтетическими данными, без загрузки приложения и подключения к БД. sh -n обоих новых wrappers и git diff --check прошли. Полный набор из 69 тестов здесь не перезапускался и НЕ считается проверкой PostgreSQL: fixture использует SQLite, тест CLI подменяет psycopg.connect.
По чтению кода: dry-run использует SERIALIZABLE READ ONLY и rollback; apply — одну транзакцию с advisory lock; SQL параметризован; заполненные поля импортера не затираются; csv_enrichment сохраняется crawler, обычные stale-записи без этого ключа продолжают удаляться. Документированные column grants/sequence USAGE соответствуют запросам; wrappers фиксируют команды, пути, контейнер и UID; предусмотрены root-owned ключи/скрипты, NOLOGIN, завершение DB-сессий и отзыв grants. Фактические PUBLIC grants, SSH-конфигурация и работа на PostgreSQL не проверены. Перед применением требуется отдельная проверка на изолированном PostgreSQL с минимальной ролью, повторным импортом и настоящим rollback; production/VPS в этом review не затронуты.
Исправлений, push, создания PR, merge или действий на production/VPS не выполнялось.
Независимое review commit 72afb3104935635edca423db4fe7c4e1c8e6c406: REQUEST_CHANGES.
Origin сверён с clone_url репозитория PR. Через GET /repos/admin/miem_workers/pulls/54 подтверждён автор codex (id 6), через GET /user — reviewer agent (id 7); идентичности разные. Перед публикацией head повторно проверен, изменений нет.
Проверен полный diff всех 11 файлов и окружающий поток: parser → _upsert_employee → savepoint публикаций → сопоставление/обновление/очистка; модель, SQL миграция, импортер, тесты, инструкции grants, SSH wrappers и отзыв доступа.
Замечания, препятствующие approval:
1. [P1] Crawler может сопоставить одну CSV-запись с несколькими разными HSE publication_id и молча потерять первую статью. imported включает также уже привязанные и ранее обогащённые HSE-записи. Для одной CSV-статьи Same/2024 без DOI и двух входящих статей hse-A и hse-B с этим названием/годом оба вызова _match_imported_publication возвращают тот же id. После двух _apply_publication остаются только publication_id=hse-B, его authors и raw_data; данные hse-A перезаписаны без ValueError/rollback. Parser сохраняет разные HSE id, поэтому они действительно могут попасть в один обход. Необходимо контролировать соответствие в обе стороны и конфликт уже установленного HSE id; неоднозначность должна откатывать savepoint, а не зависеть от порядка статей. Нужен регрессионный тест двух HSE id на одну CSV-запись, включая уже привязанную запись.
2. [P2] Apply предполагает наличие raw_data во всех действиях, хотя plan удаляет неизменённые поля. Если csv_enrichment уже содержит исходную строку, а канонический year пуст, plan корректно возвращает update с values={year: 2024}. Строка 158 затем вызывает KeyError на values[raw_data]. Dry-run такого плана успешен, apply откатывает весь импорт. Jsonb нужно применять только при наличии raw_data; проверить настоящий путь apply для обновления одного канонического поля без изменения JSON.
3. [P2] Ранний csv_duplicate отбрасывает поздние непустые метаданные. Для двух строк с одинаковыми сотрудником/DOI, где первая без Scopus/квартиля, а вторая содержит Scopus=new-id и квартиль=Q1, остаётся одна вставка, но оба дополнительных значения отсутствуют. Повторный импорт в том же порядке также их не добавит. Это нарушает описанный приоритет первого непустого значения и сохранение исходных CSV-метаданных. Нужно дополнять пустые метаданные у повторов, сохраняя уже заполненные значения и одну публикацию.
Проверки: воспроизведения выполнены на функциях именно этого head в памяти со стандартной библиотекой и синтетическими данными, без загрузки приложения и подключения к БД. sh -n обоих новых wrappers и git diff --check прошли. Полный набор из 69 тестов здесь не перезапускался и НЕ считается проверкой PostgreSQL: fixture использует SQLite, тест CLI подменяет psycopg.connect.
По чтению кода: dry-run использует SERIALIZABLE READ ONLY и rollback; apply — одну транзакцию с advisory lock; SQL параметризован; заполненные поля импортера не затираются; csv_enrichment сохраняется crawler, обычные stale-записи без этого ключа продолжают удаляться. Документированные column grants/sequence USAGE соответствуют запросам; wrappers фиксируют команды, пути, контейнер и UID; предусмотрены root-owned ключи/скрипты, NOLOGIN, завершение DB-сессий и отзыв grants. Фактические PUBLIC grants, SSH-конфигурация и работа на PostgreSQL не проверены. Перед применением требуется отдельная проверка на изолированном PostgreSQL с минимальной ролью, повторным импортом и настоящим rollback; production/VPS в этом review не затронуты.
Исправлений, push, создания PR, merge или действий на production/VPS не выполнялось.
[P1] Один imported target повторно используется для разных HSE publication_id. CSV Same/2024 без DOI + входящие hse-A и hse-B с одинаковым названием/годом → тот же id сначала получает hse-A, затем hse-B; authors/raw_data первой статьи теряются без rollback. Проверяйте уже привязанный publication_id и неоднозначность в обратную сторону; нужен тест двух HSE id на один CSV target.
[P1] Один imported target повторно используется для разных HSE publication_id. CSV Same/2024 без DOI + входящие hse-A и hse-B с одинаковым названием/годом → тот же id сначала получает hse-A, затем hse-B; authors/raw_data первой статьи теряются без rollback. Проверяйте уже привязанный publication_id и неоднозначность в обратную сторону; нужен тест двух HSE id на один CSV target.
[P2] csv_duplicate пропускается до объединения метаданных. Если первая строка того же сотрудника/DOI имеет пустой Scopus/квартиль, а вторая их заполняет, эти значения теряются; повторный импорт также их не добавляет. Дополняйте пустые метаданные у повторов, сохраняя первую непустую информацию и одну запись.
[P2] csv_duplicate пропускается до объединения метаданных. Если первая строка того же сотрудника/DOI имеет пустой Scopus/квартиль, а вторая их заполняет, эти значения теряются; повторный импорт также их не добавляет. Дополняйте пустые метаданные у повторов, сохраняя первую непустую информацию и одну запись.
[P2] plan удаляет неизменённый raw_data из values. При уже сохранённом csv_enrichment и пустом year получается update values={year: 2024}; здесь возникает KeyError, хотя dry-run успешен. Оборачивайте raw_data в Jsonb только при наличии ключа; проверьте apply для обновления канонического поля без изменения JSON.
[P2] plan удаляет неизменённый raw_data из values. При уже сохранённом csv_enrichment и пустом year получается update values={year: 2024}; здесь возникает KeyError, хотя dry-run успешен. Оборачивайте raw_data в Jsonb только при наличии ключа; проверьте apply для обновления канонического поля без изменения JSON.
Повторное независимое review: APPROVE для актуального head 25eb6481f7. Блокирующих замечаний не обнаружено; все три замечания review #133 исправлены.
Origin повторно сверён с репозиторием admin/miem_workers. API подтвердил автора codex (id 6) и текущего reviewer agent (id 7). Непосредственно перед публикацией head повторно проверен.
Проверен полный актуальный diff main 111ee152… → head 25eb648… всех 11 файлов, а также изменения после первого review и окружающий код parser, моделей, _upsert_employee, транзакций crawler, формирования и отображения отчёта.
Исправления:
Разный непустой HSE publication_id у CSV-записи теперь вызывает ValueError в _apply_publication до изменения полей. Проверка действует после любого пути сопоставления. Пустой входящий ID сохраняет существующую привязку. Новая параметризация покрывает оба порядка hse-A/hse-B и исходную запись как без привязки, так и с hse-A; проверяет сохранность id, publication_id, source_hash, raw_data и authors после rollback, а также текст ошибки в отчёте.
Jsonb применяется только при наличии raw_data в values. Регрессионный CLI-тест проходит apply для values={year: 2024}, проверяет UPDATE только year/updated_at и сохранность JSON.
Повтор CSV больше не пропускается до объединения метаданных: поздние значения дополняют пустые поля, первое непустое значение сохраняется. Тест проверяет одну вставку, поздние Scopus/квартиль/WoS, отсутствие новых действий при повторном импорте и явное сообщение о конфликтах метаданных без раскрытия значений.
Границы отката при конфликте HSE ID:
db.begin_nested() охватывает синхронизацию публикаций одного текущего сотрудника. Откатываются все изменения публикаций в этой пачке, в том числе обновления/вставки неконфликтующих статей той же пачки; ранее сохранённые публикации остаются целы.
Изменения карточки, tabs и snapshot выполняются и flush до этого savepoint. Обработчик ловит ошибку после отката savepoint, добавляет CrawlError во внешнюю транзакцию и возвращает управление; затем выполняется синхронизация news links и обычный commit сотрудника.
Обработка других сотрудников продолжается. Дополнительно проверен сценарий «сотрудник до конфликта → конфликтный сотрудник → сотрудник после»: сохранены обе несвязанные публикации, исходная CSV-запись и её authors/raw_data/hash; новая карточка конфликтного сотрудника и snapshot сохранились.
Ошибка видна через run_detail_payload(...)[errors] и раздел «Ошибки запуска» в шаблоне: содержит id записи БД и оба конфликтующих HSE ID. Существующий локальный обработчик не увеличивает агрегированный run.error_count; для этого конфликта источником подробностей является errors.
Проверки reviewer: 14 целевых случаев из актуальных тестов выполнены успешно, включая 4 комбинации HSE-конфликта, повторный crawl с сохранением CSV и очисткой обычных stale-записей, неоднозначность с rollback, сопоставление/повтор CSV и оба CLI-регрессионных пути. Дополнительный сценарий трёх сотрудников также прошёл с реальными SQLAlchemy savepoints и autoflush=False как в runtime.
Для соблюдения read-only режима исходники загружались из Git в память; SQLite использовалась только :memory:, CSV/JSON файлы CLI — в памяти, соединение CLI подменялось тестовым. app.db заменён минимальным Base без загрузки settings/.env и подключения приложения. Это целевые проверки, а не полный pytest-прогон. sh -n обоих wrappers и git diff --check прошли.
Ограничения: SQLite и подменённое CLI-соединение НЕ подтверждают работу на PostgreSQL, SERIALIZABLE/grants или фактическую SSH-конфигурацию. Документированные минимальные column grants, sequence USAGE, ограниченные wrappers и процедура отзыва доступа проверены по коду и инструкции; production-доступ не использовался. Перед применением остаётся необходимой отдельная проверка на изолированном PostgreSQL с минимальной ролью и настоящий owner-run dry-run по инструкции.
Production/VPS не затронуты; правок, push, создания PR и merge не выполнялось.
Повторное независимое review: APPROVE для актуального head 25eb6481f79c9cfdb2779a8af1b845e955ce984a. Блокирующих замечаний не обнаружено; все три замечания review #133 исправлены.
Origin повторно сверён с репозиторием admin/miem_workers. API подтвердил автора codex (id 6) и текущего reviewer agent (id 7). Непосредственно перед публикацией head повторно проверен.
Проверен полный актуальный diff main 111ee152… → head 25eb648… всех 11 файлов, а также изменения после первого review и окружающий код parser, моделей, _upsert_employee, транзакций crawler, формирования и отображения отчёта.
Исправления:
1. Разный непустой HSE publication_id у CSV-записи теперь вызывает ValueError в _apply_publication до изменения полей. Проверка действует после любого пути сопоставления. Пустой входящий ID сохраняет существующую привязку. Новая параметризация покрывает оба порядка hse-A/hse-B и исходную запись как без привязки, так и с hse-A; проверяет сохранность id, publication_id, source_hash, raw_data и authors после rollback, а также текст ошибки в отчёте.
2. Jsonb применяется только при наличии raw_data в values. Регрессионный CLI-тест проходит apply для values={year: 2024}, проверяет UPDATE только year/updated_at и сохранность JSON.
3. Повтор CSV больше не пропускается до объединения метаданных: поздние значения дополняют пустые поля, первое непустое значение сохраняется. Тест проверяет одну вставку, поздние Scopus/квартиль/WoS, отсутствие новых действий при повторном импорте и явное сообщение о конфликтах метаданных без раскрытия значений.
Границы отката при конфликте HSE ID:
- db.begin_nested() охватывает синхронизацию публикаций одного текущего сотрудника. Откатываются все изменения публикаций в этой пачке, в том числе обновления/вставки неконфликтующих статей той же пачки; ранее сохранённые публикации остаются целы.
- Изменения карточки, tabs и snapshot выполняются и flush до этого savepoint. Обработчик ловит ошибку после отката savepoint, добавляет CrawlError во внешнюю транзакцию и возвращает управление; затем выполняется синхронизация news links и обычный commit сотрудника.
- Обработка других сотрудников продолжается. Дополнительно проверен сценарий «сотрудник до конфликта → конфликтный сотрудник → сотрудник после»: сохранены обе несвязанные публикации, исходная CSV-запись и её authors/raw_data/hash; новая карточка конфликтного сотрудника и snapshot сохранились.
- Ошибка видна через run_detail_payload(...)[errors] и раздел «Ошибки запуска» в шаблоне: содержит id записи БД и оба конфликтующих HSE ID. Существующий локальный обработчик не увеличивает агрегированный run.error_count; для этого конфликта источником подробностей является errors.
Проверки reviewer: 14 целевых случаев из актуальных тестов выполнены успешно, включая 4 комбинации HSE-конфликта, повторный crawl с сохранением CSV и очисткой обычных stale-записей, неоднозначность с rollback, сопоставление/повтор CSV и оба CLI-регрессионных пути. Дополнительный сценарий трёх сотрудников также прошёл с реальными SQLAlchemy savepoints и autoflush=False как в runtime.
Для соблюдения read-only режима исходники загружались из Git в память; SQLite использовалась только :memory:, CSV/JSON файлы CLI — в памяти, соединение CLI подменялось тестовым. app.db заменён минимальным Base без загрузки settings/.env и подключения приложения. Это целевые проверки, а не полный pytest-прогон. sh -n обоих wrappers и git diff --check прошли.
Ограничения: SQLite и подменённое CLI-соединение НЕ подтверждают работу на PostgreSQL, SERIALIZABLE/grants или фактическую SSH-конфигурацию. Документированные минимальные column grants, sequence USAGE, ограниченные wrappers и процедура отзыва доступа проверены по коду и инструкции; production-доступ не использовался. Перед применением остаётся необходимой отдельная проверка на изолированном PostgreSQL с минимальной ролью и настоящий owner-run dry-run по инструкции.
Production/VPS не затронуты; правок, push, создания PR и merge не выполнялось.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Добавляет разовый импортер Статьи.csv: по умолчанию read-only dry-run, применение одной транзакцией, сопоставление только с существующими сотрудниками, заполнение пустых полей и отдельные CSV-метаданные, отчёт insert/update/skip. Нет удаления данных или изменений схемы.
Crawler ранее удалял CSV-вставки при непустом ответе ВШЭ и стирал метаданные при обновлении найденных статей. Теперь сохраняет записи и csv_enrichment, использует импортированную запись при последующем появлении статьи у ВШЭ и откатывает синхронизацию при неоднозначности. Обычная очистка устаревших HSE-записей сохранена.
Документация: docs/publication-import.md — затронутые столбцы и sequence, минимальные grants, временная роль, ограниченные SSH-команды и отзыв доступа. Версия 0.10.1.
Проверки: 69 локальных тестов, включая повторный crawl после применения плана импорта, отсутствие дубликатов и rollback при неоднозначном соответствии; shell syntax и git diff --check. Это SQLite и тестовые соединения, не проверка настоящего PostgreSQL. Production, роли БД и работа crawler не менялись. Требуется независимое ревью перед дальнейшими действиями.
Независимое review commit
72afb31049: REQUEST_CHANGES.Origin сверён с clone_url репозитория PR. Через GET /repos/admin/miem_workers/pulls/54 подтверждён автор codex (id 6), через GET /user — reviewer agent (id 7); идентичности разные. Перед публикацией head повторно проверен, изменений нет.
Проверен полный diff всех 11 файлов и окружающий поток: parser → _upsert_employee → savepoint публикаций → сопоставление/обновление/очистка; модель, SQL миграция, импортер, тесты, инструкции grants, SSH wrappers и отзыв доступа.
Замечания, препятствующие approval:
[P1] Crawler может сопоставить одну CSV-запись с несколькими разными HSE publication_id и молча потерять первую статью. imported включает также уже привязанные и ранее обогащённые HSE-записи. Для одной CSV-статьи Same/2024 без DOI и двух входящих статей hse-A и hse-B с этим названием/годом оба вызова _match_imported_publication возвращают тот же id. После двух _apply_publication остаются только publication_id=hse-B, его authors и raw_data; данные hse-A перезаписаны без ValueError/rollback. Parser сохраняет разные HSE id, поэтому они действительно могут попасть в один обход. Необходимо контролировать соответствие в обе стороны и конфликт уже установленного HSE id; неоднозначность должна откатывать savepoint, а не зависеть от порядка статей. Нужен регрессионный тест двух HSE id на одну CSV-запись, включая уже привязанную запись.
[P2] Apply предполагает наличие raw_data во всех действиях, хотя plan удаляет неизменённые поля. Если csv_enrichment уже содержит исходную строку, а канонический year пуст, plan корректно возвращает update с values={year: 2024}. Строка 158 затем вызывает KeyError на values[raw_data]. Dry-run такого плана успешен, apply откатывает весь импорт. Jsonb нужно применять только при наличии raw_data; проверить настоящий путь apply для обновления одного канонического поля без изменения JSON.
[P2] Ранний csv_duplicate отбрасывает поздние непустые метаданные. Для двух строк с одинаковыми сотрудником/DOI, где первая без Scopus/квартиля, а вторая содержит Scopus=new-id и квартиль=Q1, остаётся одна вставка, но оба дополнительных значения отсутствуют. Повторный импорт в том же порядке также их не добавит. Это нарушает описанный приоритет первого непустого значения и сохранение исходных CSV-метаданных. Нужно дополнять пустые метаданные у повторов, сохраняя уже заполненные значения и одну публикацию.
Проверки: воспроизведения выполнены на функциях именно этого head в памяти со стандартной библиотекой и синтетическими данными, без загрузки приложения и подключения к БД. sh -n обоих новых wrappers и git diff --check прошли. Полный набор из 69 тестов здесь не перезапускался и НЕ считается проверкой PostgreSQL: fixture использует SQLite, тест CLI подменяет psycopg.connect.
По чтению кода: dry-run использует SERIALIZABLE READ ONLY и rollback; apply — одну транзакцию с advisory lock; SQL параметризован; заполненные поля импортера не затираются; csv_enrichment сохраняется crawler, обычные stale-записи без этого ключа продолжают удаляться. Документированные column grants/sequence USAGE соответствуют запросам; wrappers фиксируют команды, пути, контейнер и UID; предусмотрены root-owned ключи/скрипты, NOLOGIN, завершение DB-сессий и отзыв grants. Фактические PUBLIC grants, SSH-конфигурация и работа на PostgreSQL не проверены. Перед применением требуется отдельная проверка на изолированном PostgreSQL с минимальной ролью, повторным импортом и настоящим rollback; production/VPS в этом review не затронуты.
Исправлений, push, создания PR, merge или действий на production/VPS не выполнялось.
@@ -423,2 +427,2 @@if not existing:existing = EmployeePublication(employee_id=employee.id, source_hash=source_hash, title=_publication_title(publication))if not existing:existing = _match_imported_publication(imported, publication)[P1] Один imported target повторно используется для разных HSE publication_id. CSV Same/2024 без DOI + входящие hse-A и hse-B с одинаковым названием/годом → тот же id сначала получает hse-A, затем hse-B; authors/raw_data первой статьи теряются без rollback. Проверяйте уже привязанный publication_id и неоднозначность в обратную сторону; нужен тест двух HSE id на один CSV target.
@@ -0,0 +72,4 @@skip("year_conflict")continuekey = (employee_id, identifier or (normalized(title), year))if key in seen:[P2] csv_duplicate пропускается до объединения метаданных. Если первая строка того же сотрудника/DOI имеет пустой Scopus/квартиль, а вторая их заполняет, эти значения теряются; повторный импорт также их не добавляет. Дополняйте пустые метаданные у повторов, сохраняя первую непустую информацию и одну запись.
@@ -0,0 +155,4 @@if args.apply:for action in actions:values = dict(action["values"])values["raw_data"] = Jsonb(values["raw_data"])[P2] plan удаляет неизменённый raw_data из values. При уже сохранённом csv_enrichment и пустом year получается update values={year: 2024}; здесь возникает KeyError, хотя dry-run успешен. Оборачивайте raw_data в Jsonb только при наличии ключа; проверьте apply для обновления канонического поля без изменения JSON.
Повторное независимое review: APPROVE для актуального head
25eb6481f7. Блокирующих замечаний не обнаружено; все три замечания review #133 исправлены.Origin повторно сверён с репозиторием admin/miem_workers. API подтвердил автора codex (id 6) и текущего reviewer agent (id 7). Непосредственно перед публикацией head повторно проверен.
Проверен полный актуальный diff main 111ee152… → head 25eb648… всех 11 файлов, а также изменения после первого review и окружающий код parser, моделей, _upsert_employee, транзакций crawler, формирования и отображения отчёта.
Исправления:
Границы отката при конфликте HSE ID:
Проверки reviewer: 14 целевых случаев из актуальных тестов выполнены успешно, включая 4 комбинации HSE-конфликта, повторный crawl с сохранением CSV и очисткой обычных stale-записей, неоднозначность с rollback, сопоставление/повтор CSV и оба CLI-регрессионных пути. Дополнительный сценарий трёх сотрудников также прошёл с реальными SQLAlchemy savepoints и autoflush=False как в runtime.
Для соблюдения read-only режима исходники загружались из Git в память; SQLite использовалась только :memory:, CSV/JSON файлы CLI — в памяти, соединение CLI подменялось тестовым. app.db заменён минимальным Base без загрузки settings/.env и подключения приложения. Это целевые проверки, а не полный pytest-прогон. sh -n обоих wrappers и git diff --check прошли.
Ограничения: SQLite и подменённое CLI-соединение НЕ подтверждают работу на PostgreSQL, SERIALIZABLE/grants или фактическую SSH-конфигурацию. Документированные минимальные column grants, sequence USAGE, ограниченные wrappers и процедура отзыва доступа проверены по коду и инструкции; production-доступ не использовался. Перед применением остаётся необходимой отдельная проверка на изолированном PostgreSQL с минимальной ролью и настоящий owner-run dry-run по инструкции.
Production/VPS не затронуты; правок, push, создания PR и merge не выполнялось.