This commit is contained in:
arseny.omelchenko committed 2026-11-13 22:02:30 +03:00
commit 95cacc79c2
34 files changed
+1394

No files matched your search

+21
View File
@@ -0,0 +1,21 @@
# Отчет приемки
Приемка завершена 2026-11-13 20:26:46 +03:00. Фактическое календарное время 8 минут 33 секунды; это не сумма агентного времени. Ориентир 2–3 часа не исчерпан. Незавершенных обязательных пунктов нет.
README-команды генератор→ETL→SQL проверены исполнителем в новой docs/verification/: тот же SHA256 входа, 301/290/11, 99119395 копеек, SQL 3/30/1; повтор тестов 6 OK (0.132s). Доказательства: docs/verification/RUN_LOG.md и coordination/handoffs/documentation-engineer.md.
Начало работы 2026-11-13 20:18:13 +03:00. Это учебный локальный ETL на синтетических данных.
| Требование | Файл | Проверка | Результат |
|---|---|---|---|
| Грязные данные с seed | scripts/generate_data.py, data/raw/orders.csv | генерация seed 42 | 301 строка |
| Очистка и точные деньги | src/pipeline.py | ручная независимая фикстура unittest | 2 факта, 2080 копеек |
| Дубли, конфликты, пропуски, даты | tests/test_pipeline.py | приоритеты и первая валидная запись | PASS |
| Баланс и причины | reports/etl/quality.json, rejected.csv | 301=290+11, сумма причин 11 | PASS |
| Факты и агрегаты | output/sales.sqlite | сумма обеих таблиц | 99119395 копеек |
| Идемпотентность | tests/test_pipeline.py | два запуска, сортированные логические данные | PASS |
| Пустой и весь плохой вход | tests/test_pipeline.py | корректная пустая замена | PASS |
| Атомарность БД | tests/test_pipeline.py | SQL trigger вызывает сбой INSERT после DELETE | прежние данные сохранены |
| Три SQL | sql/*.sql, reports/sql/*.csv | реальный runner, пустая БД, повтор CSV | 3 категории, 30 дней, 1 сигнал |
| Независимая приемка | tests/test_pipeline.py | тимлид: unittest discover -s tests -v | 6 tests, 0.129s, OK |
Качество: missing_required=2, invalid_date=2, invalid_quantity=2, invalid_price=3, duplicate=1, conflicting_key=1. Принятые исправленные=290 (синтетический генератор намеренно варьирует представление). Валюта RUB, суммы в копейках.
Ограничения: CSV целиком в памяти; полная перезагрузка, порядок конфликтующих строк значим; три формата дат без времени; одна валюта; возвраты не моделируются. Общей транзакции БД и файлов отчетов нет: при сбое публикации отчетов нужен повтор. Аномалия — сигнал, не дефект исходной записи. Внешняя эксплуатация, большие данные и конкурентные запуски не проверялись.
+9
View File
@@ -0,0 +1,9 @@
# Рабочий журнал ИИ
20:26:46: приемка завершена, фактическое время с 20:18:13 — 8 минут 33 секунды. Тимлид просмотрел код, SQL и README, самостоятельно повторил 6 unittest (0.129s, OK). Документатор выполнил все три CLI в новой docs/verification/, получил идентичные качество и SQL результаты, затем 6 тестов OK. SQL исполнитель также подтвердил пустой набор и воспроизводимость. Обязательное выполнено; ограничения отражены в README/ACCEPTANCE. Никаких оценок работодателя не выставлялось.
20:23: первая волна завершена. Инженер сообщил 301=290+11, 99119395 копеек, integrity_check ok и равенство повторных логических данных. Тестировщик выполнил 6 тестов. Его первая попытка имела 4 WinError32 при cleanup: sqlite context manager не закрывал соединения; исправлено contextlib.closing, повтор PASS. Дефектов ETL тесты не выявили.
Вторая волна: тот же инженер получил роль sql-pro и владение sql/reports/sql; тот же тестировщик получил роль documentation-engineer и README/docs, обязан проверить запуск в новой чистой выходной директории. Это реальное переиспользование двух работников, не новые агенты.
20:21: DOCX прочитан через OOXML для сверки текста после чтения documents skill; временный Markdown также прочитан. Раздел 4 совпадает. Python bundled 3.12.14 проверен. Команда инженеру: реализовать контракт, генератор seed 42, CLI/API, итоговую БД и отчеты; владение src/scripts генератора/data/raw/output/reports/etl. Команда тестировщику: независимо задать ручные ожидаемые значения, unittest очистки, баланса, идемпотентности, пустых входов и rollback; владение tests, только temp БД. Оба получили запрет откатывать чужое и менять общий контракт без согласования.
Это рабочий журнал существенных заданий и результатов, не полная стенограмма инструментов.
2026-11-13 20:18:13 +03:00: root начал проверку workspace и источников. Пользователь поручил команду root/teamlead/два исполнителя волнами, строгие ownership и доказательства.
Root поручил teamlead контракт, распределение, интеграцию и приемку без дублирования кода исполнителей. AGENTS.md не найден в workspace и родителях. Все временные источники существуют. Существующий DATA_ENGINEER_PROMPT.md сохраняется.
Ошибка окружения: python --version и py --version попали в недоступные WindowsApps aliases. Решение: bundled Python, найденный load_workspace_dependencies.
+4
View File
@@ -0,0 +1,4 @@
# Бриф
Только раздел 4 Data-инженер: локальный воспроизводимый ETL, грязный синтетический CSV, SQLite, качество, три SQL и результаты. Без внешних сервисов. Пользовательский DATA_ENGINEER_PROMPT.md не изменять.
Готовность: работающая БД, доказанные тесты очистки/баланса/идемпотентности/атомарности, README с проверенным запуском, журнал ИИ, приемка.
Начало: 2026-11-13 20:18:13 +03:00. Ориентир 2–3 часа, фиксируем фактическое время.
+10
View File
@@ -0,0 +1,10 @@
# Контракт
Уточнение v1.2: corrected_rows сравнивает канонические представления всех шести CSV полей (также quantity 01→1 и unit_price 1→1.00). Сообщено обоим работникам.
Уточнение v1.1 (до реализации): corrected_rows считает принятые строки с измененными нормализованными текстовыми полями, включая дату. Переполнение общей суммы int64 завершает запуск ошибкой до записи. Сообщено обоим работникам.
CSV UTF-8: order_id,line_id,order_date,category,quantity,unit_price. Зерно: строка заказа, ключ (order_id,line_id), оба непустые строки после strip. Валюта RUB, цена Decimal с максимум двумя дробными знаками, хранение копеек INTEGER. quantity положительное целое; цена положительная. Нули/отрицательные отклоняются. Выручка quantity*unit_price_kopecks.
Даты строго YYYY-MM-DD, DD.MM.YYYY, YYYY/MM/DD; slash DD/MM/YYYY не поддерживается и отклоняется, угадывания нет. День календарный без времени. Категория: strip, схлопывание whitespace, casefold; непустая, без выдуманных замен.
Валидация до дедупликации. Первая валидная строка ключа побеждает; следующие с равными нормализованными бизнес-полями — duplicate, с отличающимися — conflicting_key. Порядок файла значим. Основные причины по приоритету: missing_required, invalid_date, invalid_quantity, invalid_price, duplicate, conflicting_key. Для malformed CSV допустим отказ всего запуска до записи. Исправленные принятые строки учитывать отдельно.
SQLite facts: order_id TEXT,line_id TEXT,order_date TEXT,category TEXT,quantity INTEGER,unit_price_kopecks INTEGER,revenue_kopecks INTEGER; PK(order_id,line_id). daily_category: order_date,category,revenue_kopecks INTEGER, PK(order_date,category). source_row разрешено дополнительно в facts. Все суммы ограничить SQLite int64.
Запуск: python scripts/generate_data.py --output data/raw/orders.csv --seed 42; python -m src.pipeline --input data/raw/orders.csv --db output/sales.sqlite --reports reports/etl. API run_pipeline(input_path, db_path, reports_dir). Полная замена обеих бизнес-таблиц в одной транзакции; rollback при сбое, пустой/весь отклоненный CSV очищает таблицы корректно.
Отчеты: reports/etl/quality.json (input_rows,accepted_rows,rejected_rows,corrected_rows,reasons,revenue_kopecks), rejected.csv (source_row,reason и исходные поля). input=accepted+rejected, сумма reasons=rejected. Номер source_row — физическая CSV строка начиная с 2 (встроенные переводы строк запретить либо документировать логический номер).
SQL последующая волна: top_categories.sql, daily_dynamics.sql (календарь min..max, отсутствующие дни=0), anomalies.sql (объяснимое правило и порог). Результаты CSV в reports/sql. Только инженер пишет итоговую БД и ETL отчеты; тесты только временные БД. Тимлид вправе интеграционно запускать CLI после сдачи инженера.
+2
View File
@@ -0,0 +1,2 @@
# Решения
v1: стандартная библиотека Python и SQLite: воспроизводимость без установки зависимостей. Деньги в копейках: точные суммы. Первый валидный ключ побеждает: простая детерминированная политика без ненадежного определения новизны. Полная транзакционная замена: небольшая учебная выгрузка, не инкрементальное промышленное хранилище.
+9
View File
@@ -0,0 +1,9 @@
# Статус
| Задача | Владелец | Статус | Зависимость | Следующее |
|---|---|---|---|---|
| Контракт | teamlead | done | требования | реализация |
| ETL | data-engineer | done | v1.2 | 301=290+11; БД готова |
| Тесты | test-automator | done | v1.2 | 6 unittest OK, повторено тимлидом |
| SQL | sql-pro (переиспользован инженер) | done | БД | 3/30/1 строк результатов |
| Документация | documentation-engineer (переиспользован тестировщик) | done | результаты | чистый запуск PASS |
| Приемка | teamlead | done | все этапы | ACCEPTANCE.md; выдача root |
+17
View File
@@ -0,0 +1,17 @@
# Передача data-engineer
Владение: src/, scripts/generate_data.py, data/raw/, output/sales.sqlite, reports/etl/. Реализованы stdlib генератор seed=42 и строгий ETL согласно контракту v1 (уточнение corrected_rows согласовано с тимлидом: канонические представления всех 6 полей).
Выполнено Python 3.12.14 из bundled runtime:
```
python scripts/generate_data.py --output data/raw/orders.csv --seed 42
python -m src.pipeline --input data/raw/orders.csv --db output/sales.sqlite --reports reports/etl
```
Фактический результат: 301 входных = 290 принятых + 11 отклоненных. Причины: missing_required 2, invalid_date 2, invalid_quantity 2, invalid_price 3, duplicate 1, conflicting_key 1. corrected_rows=290. Выручка 99119395 копеек. Вход SHA256 a7816b666a8b3dc8833f937970cab2bc7206b6fd44ea3413547eb06f17e1cfe5.
Повторный запуск через run_pipeline и сравнение SELECT * ORDER BY бизнес-ключи: PASS; 290 фактов, 87 агрегатов. PRAGMA integrity_check=ok. SUM(facts)=SUM(daily_category)=99119395.
Стратегия: CSV проверяется полностью до БД, SQLite BEGIN IMMEDIATE включает CREATE IF NOT EXISTS, DELETE и INSERT, rollback при ошибке. Тестировщику сообщен интерфейс и возможность инъекции сбоя BEFORE INSERT trigger. Номера исходных строк физические; многострочные значения запрещены ошибкой всего запуска. Нулевой байтовый вход допустим, ошибочный заголовок нет.
Ограничения: вся выгрузка в памяти; полная замена, не инкрементальная загрузка. Публикация filesystem отчетов после commit БД не имеет общей транзакции с SQLite: при сбое публикации повторить CLI. Итоговая БД и reports/etl могут перезаписываться повторным запуском осознанно, пользовательские файлы не затронуты. Отсутствие 13 января и пик 23 января намеренно заложены в синтетические валидные продажи.
Далее: независимые тесты, SQL и документация; владелец итоговой БД передает право интеграционного запуска тимлиду.
@@ -0,0 +1,7 @@
# Передача документации
Созданы README.md на русском, docs/INTERVIEW.md и docs/verification/RUN_LOG.md. В README перечислены источники артефактов, схема и семантика, форматы дат, политика дублей/конфликтов, точные деньги, фактическое качество, все три SQL и результаты, границы атомарности SQLite/файловых отчетов, ограниченность учебного решения.
Чистый запуск выполнен на Python 3.12.14 в docs/verification/: генератор → ETL → SQL, все exit 0; 301/290/11, 99119395 копеек, SQL 3/30/1. После этого повторены 6 unittest: OK, 0.132s, exit 0. Команды и выходные артефакты сохранены в docs/verification/.
Существующие пользовательские файлы и итоговая БД не изменялись этой ролью. Фактическое общее время и финальная приемка оформляются тимлидом в coordination/ACCEPTANCE.md.
+14
View File
@@ -0,0 +1,14 @@
# Передача sql-pro
Владение второй волны: sql/, reports/sql/, этот handoff. Итоговая БД открывается URI mode=ro; runner использует одну read transaction на все три запроса.
Выполнено Python 3.12.14:
```
python sql/run_queries.py --db output/sales.sqlite --output reports/sql
```
Результат: top_categories 3 строки, daily_dynamics 30 строк, anomalies 1 строка. Категории (копейки): книги 39904885; электроника 33008050; дом 26206460. Динамика покрывает 2026-01-01..2026-01-30, 2026-01-13 = 0; изменение первого дня NULL (в CSV пусто).
Аномалия: 2026-01-23, выручка 45144920 коп., сумма предыдущих семи календарных дней 13009083 коп. Порог: выручка > трех средних предыдущих 7 дней при 7 днях истории и ненулевой базе. Точный целочисленный порог floor(13009083*3/7)=5575321 коп. Это аналитический сигнал намеренно заложенного синтетического пика, не дефект строки.
Дополнительный фактический запуск в tempfile: пустой ETL дает все три SQL результата по 0 строк с CSV заголовками; повторный SQL запуск дает те же CSV байты. PASS. Сравниваются CSV, а не SQLite-файлы.
SQL использует SQLite window functions и рекурсивный календарь; полный диапазон дат строится в памяти/SQLite, для огромных диапазонов не оптимизирован. Денежные итоги остаются INTEGER. Сравнение аномалии делит сумму на 7 до умножения на 3, предотвращая SQLite integer overflow и уход во float.
+6
View File
@@ -0,0 +1,6 @@
# Передача тестов
Владелец: test-automator. Созданы tests/__init__.py и tests/test_pipeline.py. Все входы/БД/отчеты тестов изолированы в TemporaryDirectory.
Ручная фикстура из 9 строк: приняты 2 факта, 2080 копеек (2×1025 + 3×10), отклонены 7; проверены точные факты, агрегат, номера и основные причины каждой отброшенной строки. Остальные проверки: первая валидная запись ключа; отдельные line_id; повторный запуск со сравнением отсортированных логических данных; пустой и полностью отклоненный вход после непустого; откат при реальном SQL trigger RAISE(ABORT); отрицательные, нулевые, дробные, NaN/Infinity и переполнение цены.
Фактическая команда PowerShell: `& 'C:\Program Files\WindowsApps\OpenAI.CodexPrimaryRuntime.v26-1112-737-0_26.1112.737.0_x64__3k8sg7r9htsxt\dependencies\python\python.exe' -m unittest discover -s tests -v`.
Результат второго запуска: 6 tests, 0.123s, OK, exit 0. Первое выполнение: все контрактные assertions прошли, но 4 cleanup errors Windows WinError 32 в самих тестах. Причина: sqlite3 connection context manager не закрывает connection. Исправление тестов: contextlib.closing. Это ошибка тестовой инфраструктуры, не подтвержденный дефект ETL.
Ограничения: не нагрузочные тесты; SQL следующей волны не входит во владение. Следующий шаг: интеграционная приемка тимлидом и SQL.