Зачем: во время приёмки обе ветки обновили force-push (codex/fix-live-databaseea68e12→b289dd6, antigravity/fix-reject-device-shifts795bba0→1df2019, теперь наf5ac179). Вердикт по старому SHA не должен выдаваться за вердикт по новому — «на слово ничего не принимать». Что: повторный прогон стенда на новых HEAD, результат дописан в report-evidence/acceptance-*.txt, REPORT.md и NOTES. Итог тот же: fix-live-database 41 red / 13 green (K3, K4, K13 зелёные), fix-reject-device-shifts 43 red / 11 green (K13 зелёный).
26 KiB
PR: e2e-стенд на реальной PostgreSQL 17 и независимая приёмка (grok/e2e-harness)
База: codex/bootstrap-platform-foundation @ f5ac179 (содержит 331e490). Ветка перебазирована
без конфликтов. Сравнение:
https://git.ochenstarik.ru/ochenstarik/krona-staff/compare/codex/bootstrap-platform-foundation...grok/e2e-harness
Изменены только tests/e2e/**, tests/integration/tenant-isolation.test.ts,
.forgejo/workflows/ci.yml, scripts/test/** и одна строка в корневом .gitignore
(tests/e2e/evidence/, по требованию TASK-GROK-2 §1). src/, apps/, migrations/,
deploy/, package.json не тронуты. Всё, что требует правки продукта, — в
NOTES-FOR-EXECUTORS.md.
Зачем
156 зелёных тестов на поддельной БД не заметили, что создание сотрудника, подтверждение
смены и расчёт зарплаты на реальной PostgreSQL падают всегда. Стенд запускает реальный сервер
под ролью приложения без привилегий на реальной PostgreSQL 17, миграции применяет мигратор без
SUPERUSER, все токены и пароли случайные (crypto.randomBytes). Каждый сценарий проверяет
правильное поведение: красный = открытый дефект.
Что изменилось во втором круге (TASK-GROK-2)
| Пункт | Что сделано |
|---|---|
| §1 | Запуск без .cmd-обёрток: scripts/test/node-commands.mjs — всегда process.execPath + JS-точка входа из require.resolve (vitest.mjs, prettier.cjs); сервер — один процесс node --import tsx src/server.ts (без дочернего процесса CLI tsx, чтобы kill() под Windows не оставлял сироту). Проверка на Linux — tests/e2e/harness/node-commands.test.ts (в npm test) |
| §1 | tests/e2e/evidence/ убран из git и добавлен в .gitignore; в CI — артефакт e2e-evidence. Разовые доказательства (N5, N13, приёмка) — в tests/e2e/report-evidence/, скрипты туда не пишут |
| §1 | Задача windows в CI (включается переменной KRONA_WINDOWS_RUNNER=true, раннера пока нет) |
| §1 | Перебазирование на f5ac179 — без конфликтов |
| §2 | Двойные ID [владелец/мой] в названиях тестов и ключах known-defects.json |
| §3 | Новые сценарии [K6/D5], [K7/D2], [K8/D1], [K9/D3], [S9], [A4], [N12-DATE] (tests/e2e/50-money-and-errors.e2e.ts), все красные и в known-defects.json |
| §4 | Приёмка antigravity/fix-reject-device-shifts, codex/fix-format-baseline, codex/fix-live-database — таблицы ниже |
| — | Синтетическая ставка 123,45 → 123,00 ₽/ч: расчёт округляет строку до рубля (rounding_unit_minor), тест не должен зависеть от округления (выяснилось на fix-live-database) |
Как запустить
export E2E_PG_ADMIN_URL=postgres://<admin>:<pw>@127.0.0.1:55433/postgres # только создание ролей и БД
E2E_MIGRATIONS=roundtrip node scripts/test/run-e2e.mjs # храповик known-defects (как в CI)
node scripts/test/run-e2e.mjs --no-known-defects # строго: любой красный = exit 1
./scripts/test/ci-local.sh # локальный эквивалент verify/format/e2e (bash)
Таблица по ID (основная ветка f5ac179 + этот стенд)
Команда: ./scripts/test/ci-local.sh (внутри E2E_MIGRATIONS=roundtrip node scripts/test/run-e2e.mjs),
2026-09-26 ~15:28 (UTC+7), PostgreSQL 17.11:
== roundtrip OK: rolledBack=11 reapplied=11
Test Files 5 failed | 1 passed (6)
Tests 45 failed | 9 passed (54)
[run-e2e] OK: стенд работает, все красные сценарии — известные открытые дефекты
| ID владельца / мой | Цвет | Фактический вывод (первая строка assert) |
|---|---|---|
| HARNESS (×5), CTRL (×2) | GREEN | 7/7 passed — стенд и позитивные контроли |
| K1/F2 | RED | { portal: 200, payroll: 200, write: 201 } вместо 401 |
| K1/SYNC-I | RED | анонимная регистрация устройства HTTP 201 |
| K1/PILOT-1 | RED | 14 подстановок без :? (первая STANDALONE_MANAGER_TOKEN) |
| K2/PILOT-2 | RED | NODE_ENV=development у сервиса app |
| K3/N2 | RED | подтверждение смены HTTP 500 code 23502 null value in column "occurred_at" of "staff_outbox" |
| K4/N1 | RED | HTTP 500 code 42P08 inconsistent types deduced for parameter $2 |
| K5/N4 | RED | блокирован K3 (500 на подтверждении) |
| K6/D5 | RED | блокирован K3 (500 на подтверждении) |
| K7/D2 | RED | afterFirst: 22200, afterSecond: 22200 вместо 33300, 37700 |
| K8/D1 | RED | блокирован K3 (500 на подтверждении) |
| K9/D3 | RED | params.shift_rate_minor не сохранён (HTTP 200, в params нет ключа) |
| K10/F3 | RED | rawTokenInCookie: true |
| K11/F4 | RED | все попытки 401, 429 нет |
| K12/N3 | RED | подписка на https://127.0.0.1:<port> HTTP 201, 1 входящее соединение |
| K13/SYNC-A, K13/SYNC-B | RED | upsert_work_session / upsert_timesheet_entry → status: applied |
| K17/OWN-10, K17/OWN-11 | RED | 404 Route GET .../terminal/employees/:id/enrollment / PUT .../biometric-consent (нет API, C3) |
| K19/OWN-07 | RED | 404 Route POST /access-grants (нет API, C1/C2) |
| D6/OWN-01, D6/OWN-02 | RED | 404 Route POST /access-grants (нет API, C1) |
| OWN-03..06, OWN-08, OWN-09 | RED | 404 Route POST /access-grants (нет API, C1/C2) |
| S2/SYNC-J | RED | отметка 2001 года → status: applied |
| S3/SYNC-G | RED | HTTP 500 code 22007 на весь пакет |
| S4/SYNC-E | RED | отметка уволенного → applied |
| S4/SYNC-F | RED | { ownOrgUnit: null, foreign: "applied" } |
| S5/SYNC-C | RED | HTTP 500 code 42703 column "status" does not exist (блокирован SYNC-C0) |
| S5/SYNC-D | RED | изменение из портала не видно в инкрементальном pull |
| S8/SYNC-H | RED | регистрация устройства по cookie с чужим Origin HTTP 201 |
| S9 | RED | удаление точки с устройством: 23502 null value in column "tenant_id" |
| A4 | RED | 2 тела 500 с SQLSTATE/текстом PostgreSQL (POST /employees 42P08, month=2026-13 22008) |
| N9 | RED | чужой push-endpoint перепривязан HTTP 201 |
| N10 | RED | терминал: { professions: 200, units: 200 } |
| N11 | RED | импорт с неверным kind HTTP 500 code 23514 |
| N12 | RED | лишнее поле и нереальная сумма → HTTP 200 |
| N12-DATE | RED | month=2026-13 → HTTP 500 code 22008; 2026-02-30 уже 400 |
| F7 | RED | повтор Idempotency-Key создал второе событие |
| F10 | RED | мутация по cookie без Origin HTTP 201 |
| SYNC-C0 (нет ID у владельца) | RED | bootstrap pull HTTP 500 code 42703 column "status" does not exist |
| SYNC-K (нет ID у владельца) | RED | ack курсора из будущего HTTP 200 |
| SYNC-L | GREEN | отозванное устройство получает 403 (позитивный контроль) |
| PILOT-3 | GREEN | у app нет учётных данных мигратора |
| N5 (tenant-isolation) | GREEN | в npm run check с тестовой БД: Test Files 20 passed (20), Tests 196 passed (196) |
| N13 (скрипт, не vitest) | — | не воспроизведено: 0 из 30 попыток при 10/25/50 (обход K3 в одноразовой БД), см. ниже |
Сверх таблицы TASK-GROK-2 §2 (по тексту AUDIT.md): K1/SYNC-I (анонимный доступ без токенов на
/sync), K1/PILOT-1 (подстановки без :? названы в K1), K2/PILOT-2 (development в пилоте — суть K2).
Приёмка веток исполнителей (TASK-GROK-2 §4)
Способ: git worktree add --detach <dir> origin/<ветка>, поверх — tests/e2e/ и scripts/test/
из этой ветки (в ветки исполнителей ничего не коммитилось), затем
E2E_MIGRATIONS=roundtrip E2E_DATABASE_NAME=krona_staff_acc node scripts/test/run-e2e.mjs.
«Было» — основная ветка f5ac179 с тем же стендом (45 red / 9 green, храповик OK). Полные таблицы —
tests/e2e/report-evidence/acceptance-*.txt. Ни одна ветка не влита в основную
(git merge-base --is-ancestor → нет), поэтому known-defects.json не сокращён.
codex/fix-live-database @ ea68e12, перепроверено на b289dd6
== roundtrip OK: rolledBack=11 reapplied=11
Tests 41 failed | 13 passed (54)
| K13/SYNC-A | GREEN | 1/1 | зелёный — ИСПРАВЛЕН, уберите из known-defects.json |
| K13/SYNC-B | GREEN | 1/1 | зелёный — ИСПРАВЛЕН, уберите из known-defects.json |
| K3/N2 | GREEN | 1/1 | зелёный — ИСПРАВЛЕН, уберите из known-defects.json |
| K4/N1 | GREEN | 1/1 | зелёный — ИСПРАВЛЕН, уберите из known-defects.json |
| ID | Было | Стало | Доказательство |
|---|---|---|---|
| K3/N2 | RED | GREEN | было: подтверждение смены 500 23502 occurred_at; стало: passed (8 ч × 123,00 ₽ = 98400 в ledger) |
| K4/N1 | RED | GREEN | было: 500 42P08; стало: passed (201, сотрудник в БД) |
| K13/SYNC-A | RED | GREEN | было: upsert_work_session → applied; стало: passed (см. находку по fd1ec3d) |
| K13/SYNC-B | RED | GREEN | было: upsert_timesheet_entry → applied; стало: passed |
| K5/N4 | RED | RED | было: блокирован K3; стало: смена должна быть начислена ровно один раз: expected 196800n to be 98400n |
| K6/D5 | RED | RED | было: блокирован K3; стало: после отклонения оплаченной смены должно быть сторно: expected 98400n to be 0n |
| K8/D1 | RED | RED | было: блокирован K3; стало: C4 verify: HTTP 404 Route GET .../payroll/runs/:id/verify not found |
| A4 | RED | RED | было: 2 утечки; стало: 1 — POST /payroll/calculate month=2026-13 → code=22008 |
| F14 | RED | GREEN | prettier --check . → All matched files use Prettier code style! (без оверлея evidence) |
Ветку обновили force-push во время приёмки (ea68e12 → b289dd6, изменён только
tests/integration/live-postgres-remediation.test.ts); повторный прогон на b289dd6 дал те же
41 red / 13 green и ту же таблицу.
Вердикт: K3 и K4 исправлены (подтверждено на живой PostgreSQL 17, миграции roundtrip). После влития
убрать K3/N2, K4/N1 из known-defects.json. Цепочка расчёта теперь доходит до денежных дефектов:
K5 и K6 подтверждены по существу.
codex/fix-format-baseline @ fd1ec3d
Tests 43 failed | 11 passed (54)
| K13/SYNC-A | GREEN | 1/1 | зелёный — ИСПРАВЛЕН, уберите из known-defects.json |
| K13/SYNC-B | GREEN | 1/1 | зелёный — ИСПРАВЛЕН, уберите из known-defects.json |
$ node node_modules/prettier/bin/prettier.cjs --check .
All matched files use Prettier code style!
| ID | Было | Стало | Доказательство |
|---|---|---|---|
| F14 | RED (23 файла) | GREEN | All matched files use Prettier code style! |
| K13/SYNC-A | RED | GREEN | было: applied; стало: passed |
| K13/SYNC-B | RED | GREEN | было: applied; стало: passed |
| остальные | без изменений | — | compare по e2e-results.json: других отличий нет |
Находка: «style»-коммит fd1ec3d содержит функциональное исправление Antigravity.
После нормализации prettier src/domain/sync/service.ts отличается от 331e490 на 255 строк diff
и совпадает с antigravity/fix-reject-device-shifts (0 строк); tests/unit/sync.test.ts — 139 и 0.
Изменение поведения скрыто в коммите форматирования — смешение тем (AGENTS.md).
antigravity/fix-reject-device-shifts @ 795bba0, перепроверено на 1df2019
Tests 43 failed | 11 passed (54)
| K13/SYNC-A | GREEN | 1/1 | зелёный — ИСПРАВЛЕН, уберите из known-defects.json |
| K13/SYNC-B | GREEN | 1/1 | зелёный — ИСПРАВЛЕН, уберите из known-defects.json |
| ID | Было | Стало | Доказательство |
|---|---|---|---|
| K13/SYNC-A | RED | GREEN | было: upsert_work_session → applied; стало: passed |
| K13/SYNC-B | RED | GREEN | было: upsert_timesheet_entry → applied; стало: passed |
| остальные | — | — | других отличий нет |
Ветку перебазировали на f5ac179 во время приёмки (795bba0 → 1df2019); повторный прогон
на 1df2019: те же 43 red / 11 green, отличия только K13/SYNC-A/B.
Вердикт: K13 исправлен. Убрать K13/SYNC-A,
K13/SYNC-B отдельным коммитом после влития (и после исправления очистки в
sync-rejection.test.ts, TASK-GROK-2 §4.1).
Windows
- Запуск стенда переписан без
npxиnode_modules/.bin(раньшеspawn('npx')иspawn('.../.bin/tsx')падали на Windows сENOENT). Проверка на Linux:tests/e2e/harness/node-commands.test.ts— 8 тестов: команды начинаются сprocess.execPath, без.cmd/.bin/npx, файлы существуют; подwin32дочерний процесс получаетSystemRoot/TEMP, секреты родителя не наследуются. - Реальный запуск на Windows 11 — не проверено: Windows-раннера у git.ochenstarik.ru нет.
В CI добавлена задача
windows(runs-on: windows), включаемая переменнойKRONA_WINDOWS_RUNNER=true; для полного e2e нужен секретWINDOWS_E2E_PG_ADMIN_URL. scripts/test/ci-local.sh— bash, на Windows не предназначен (под Windows запускатьnode scripts/test/run-e2e.mjs).
Evidence вне git
$ E2E_MIGRATIONS=roundtrip node scripts/test/run-e2e.mjs # (повторный прогон)
[run-e2e] OK: стенд работает, все красные сценарии — известные открытые дефекты
$ git status --porcelain
# (пусто)
N5 (tenant-isolation)
До (778ba2d, очистка ролью приложения) — report-evidence/n5-before.txt:
error: permission denied for table staff_employees, exit=1. После (очистка ролью мигратора с
app.tenant_id) — report-evidence/n5-after.txt: 2 прогона, exit=0.
На f5ac179: npm run check с тестовой БД — Test Files 20 passed (20), Tests 196 passed (196).
CI (.forgejo/workflows/ci.yml)
verify:postgres:17-alpine@sha256:…, роли как в pilot (мигратор NOSUPERUSER, app NOBYPASSRLS), миграцииup → откат всех 11 → up → up,npm run checkс тестовой БД,npm audit.format: отдельно (F14 красный до влитияcodex/fix-format-baseline).e2e: PostgreSQL 17,E2E_MIGRATIONS=roundtrip, храповик; evidence — артефактe2e-evidence(actions/upload-artifact@ea165f8… # v4.6.2, Forgejo 9.0.3).windows: выключена без раннера (см. выше).docker-build: меткаdocker-host,needs: verify, только push.- Все actions закреплены SHA (F13), SHA совпадают на github.com и code.forgejo.org.
Механизм красных сценариев — храповик known-defects.json, а не «allowed to fail»: сломанный стенд,
новый красный ID или исправленный, но не вычеркнутый ID делают задачу e2e красной.
Валидация: actionlint -config-file actionlint.yaml .forgejo/workflows/ci.yml (1.7.12, метки
docker, docker-host, windows) → 0 замечаний. Локально ./scripts/test/ci-local.sh:
::: [migrate-roundtrip] OK (== roundtrip OK: rolledBack=11 reapplied=11)
::: [check] OK (Test Files 20 passed (20), Tests 196 passed (196))
::: [audit] OK (found 0 vulnerabilities)
::: [format-check] FAIL (Code style issues found in 23 files — F14)
::: [e2e] OK (Tests 45 failed | 9 passed (54), храповик OK)
N13 (гонка первого расчёта)
node scripts/test/n13-race.mjs (10/25/50 параллельных первых расчётов × 5 попыток) —
report-evidence/n13-race.txt: как есть 15/15 → 500 (K3); с обходом K3
в одноразовой БД — 0 некорректных из 30 (с подтверждённой сменой и без). Не воспроизведено, как и у
владельца; вероятная причина (гипотеза по коду) — upsert ensureDefaultPayRules сериализует расчёты
тенанта. Прогон до перебазирования, на 778ba2d.
Не проверено
- Реальный Forgejo-раннер (workflow выполнялся только локальным эквивалентом),
docker build. - Запуск на Windows 11 (раннера нет); Windows-only: DPAPI, ACL каталога данных, установщик, WinUI,
named pipe — см. тесты Codex в
apps/KronaStaffTerminal.Tests. - OWN-01..11, K8 (C4) и K9 (C5) проверяют предполагаемые контракты из NOTES.
- K5/N4, K6/D5, K8/D1 на основной ветке блокированы K3; по существу проверены только на
codex/fix-live-database. - S9 проверен удалением SQL-запросом мигратора (публичного API удаления точки нет).
- Причина невоспроизводимости N13 — гипотеза по коду.