Зачем: Codex и владельцу нужен точный список отличий интерфейса
scripts/rehome-tenant.mjs (c73bb3b) от контракта C6, чтобы выбрать один
интерфейс, а не подгонять сценарий под продукт молча.
- C6: таблица отличий (флаги --source/--target, обязательный --apply
с --actor/--backup-evidence, DATABASE_REHOME_URL, нет --json,
многострочный JSON, нет суммы журнала в dry-run) и два варианта решения.
- Раздел 8: tenant-config (как закрыть — по ACCEPTANCE-3), rehome
(интеграционный тест в check/CI всегда skipped и требует суперпользователя),
K18 (нет globals, isolation.sql зашит на ULID, личный путь в доке,
ротации нет, тесты backup не в CI).
37 KiB
Заметки для исполнителей (Codex / Antigravity)
Автор: Grok (стенд тестов и независимая приёмка). Я не меняю src/, apps/,
migrations/, deploy/; всё, что требует изменения продукта, описано здесь.
Как запускать:
# bootstrap-админ PostgreSQL 17 (только создаёт роли и БД; сервер и миграции под ним не работают)
export E2E_PG_ADMIN_URL=postgres://<admin>:<pass>@127.0.0.1:55433/postgres
node scripts/test/run-e2e.mjs # храповик known-defects (как в CI)
node scripts/test/run-e2e.mjs --no-known-defects # строгий режим: все дефекты красные
E2E_MIGRATIONS=roundtrip node scripts/test/run-e2e.mjs # + откат всех миграций перед запуском
./scripts/test/ci-local.sh # локальный эквивалент verify/format/e2e
Правило храповика. Исправили дефект → его сценарий позеленел →
run-e2e.mjs падает с «дефект исправлен, обновите known-defects.json» —
удалите ID из tests/e2e/known-defects.json в том же коммите. Новый красный
сценарий, которого нет в списке, — регрессия.
1. Предполагаемый контракт для решений владельца (OWN-01..11) — Codex, этап 4
API пока нет, поэтому сценарии tests/e2e/30-owner-decisions.e2e.ts написаны
против наиболее вероятного контракта. Если выбираете другой — поменяйте тесты и
этот раздел в том же PR, смысл проверок (кто что может и когда) менять нельзя.
Все пути относительно /api/v1/staff.
C1. Роли точки/бухгалтера/директора (standalone-аналог Core RBAC)
POST /access-grants(только главный менеджер,staff:employee:write) тело{ "role": "point_manager" | "accountant" | "director", "org_unit_ids": ["<ULID>"], "display_name": "..." }→201 { "id", "role", "org_unit_ids", "access_token" }. Токен показывается один раз, хранится как хеш (как ключи сотрудников), используется какAuthorization: Bearer.point_managerвидит/считает только своиorg_unit_ids; чужая точка →403(и для новогоPOST /payroll/batches, и для старогоPOST /payroll/calculate).- В platform-режиме те же роли приходят из Core (User ≠ Employee, AGENTS.md).
C2. Пакет зарплаты точки и согласование
| Метод и путь | Кто | Результат |
|---|---|---|
POST /payroll/batches {org_unit_id, from, to} |
accountant; point_manager своей точки | 201 {id, status:"draft", org_unit_id, lines:[{work_session_id, employee_id, org_unit_id, amount_minor}]} |
POST /payroll/batches/:id/submit |
только accountant | 200 {status:"submitted"}; point_manager → 403; повтор после подписи → 409 |
GET /notifications |
любой пользователь | 200 {notifications:[{type:"payroll.batch.submitted", subject_id:<batchId>}]}; каждому директору ровно одно уведомление на отправку |
POST /payroll/batches/:id/sign |
только director | 200 {status:"signed"}; accountant → 403; если смена пакета изменилась после отправки → 409, пакет получает status:"returned" |
POST /payroll/batches/:id/return {comment} |
director | 200 {status:"returned", return_comment} |
GET /payroll/batches/:id |
accountant, director | 200 {status, return_comment, lines:[...]} |
Инварианты, которые проверяют тесты:
- до подписи в
staff_payroll_ledgerдля сотрудников пакета нет ниaccrual, ниpayout(OWN-05); - подпись атомарно пишет
accrualиpayout; после подписиPATCH /work-sessions/:idдля смен пакета →409, пакет не отправляется повторно (OWN-06); - строка пакета принадлежит точке, где отработана смена (
staff_work_sessions.org_unit_id), а не основной точке сотрудника (OWN-09).
C3. Согласие на биометрию
PUT /employees/:id/biometric-consent{ "status": "granted" | "revoked", "document_ref": "..." }(главный менеджер) →200.GET /terminal/employees/:id/enrollment(терминальный токен) →200 { "employee_id", "registration_allowed": boolean, "reason": "consent_missing" | "consent_revoked" | null }. Без записи о согласии —false/consent_missing(OWN-10); после отзыва —false/consent_revoked(OWN-11).- Шаблоны отпечатков на сервер не передаются (docs/TERMINAL-API-REQUIREMENTS.md);
сервер хранит только факт согласия. Тот же флаг стоит отдать в
/sync/pull(employee payload).
Сейчас все OWN красные с 404 Route ... not found (C1–C3 не реализованы);
OWN-03..09 дополнительно упрутся в K3/N2 (подтверждение смены падает 500).
ID в названиях тестов — двойные «владелец/мой» ([K3/N2], [D6/OWN-01], [K17/OWN-10],
[K19/OWN-07]), по таблице TASK-GROK-2 §2 и AUDIT.md.
C4. Проверочный пересчёт подписанной ведомости (K8/D1)
GET /payroll/runs/:id/verify(правоstaff:payroll:read) →200 { "run_id", "stored_total_minor", "recalculated_total_minor", "matches": boolean }.- Пересчёт идёт по снимку версий правил, параметров и ставок, действовавших при подписи
(и ревизиям смен), а не по текущим значениям. После смены ставки
matchesостаётсяtrue.
C5. Параметры пресета в назначении оплаты (K9/D3)
PUT /employees/:id/pay-assignmentпринимаетparams: { <key>: integer }, ключи — изparam_declarationsвыбранного правила (например,shift_rate_minor,percent_bp,upsell_rate_minor,avg_check_target_minor,avg_check_bonus_minorуwaiter_upsell); неизвестный ключ → 400.GET .../pay-assignmentвозвращает их вparams.- Старые поля
rate_minor/percent_bp/guarantee_minorможно оставить как сокращения.
C6. Перенос арендатора пилота (PILOT-REHOME, TASK-CODEX-2 п.2.2)
Что проверяет tests/e2e/60-pilot-rehome.e2e.ts ([PILOT-REHOME]):
- Запуск:
DATABASE_ADMIN_URL=<админ БД> node scripts/rehome-tenant.mjs --from 01J00000000000000000000000 --to 01M2R6AC5652NPT3MG34DKN4ZP [--dry-run] [--json]. Стенд передаётDATABASE_ADMIN_URLсуперпользователя в БД стенда (E2E_DB_ADMIN_URLилиE2E_PG_ADMIN_URLс именем БД). --json: последней строкой stdout —{"tables":{"<таблица>":<строк у --from>},"ledger_amount_minor_sum":<число или строка>}. Таблицы с нулём можно не печатать.--dry-run: exit 0, те же числа, в БД ничего не меняется.- Перенос: exit 0; под
--from0 строк во всех таблицах сtenant_id(список изinformation_schema.columns, не вручную); у--toте же счётчики и та жеSUM(amount_minor)вstaff_payroll_ledger; другие арендаторы не тронуты. - В
staff_audit_logу нового арендатора появляется запись сaction, содержащимrehome(например,tenant.rehomed, старый tenant — вnew_values). - После переноса
krona_staff_appвидит тех же сотрудников (те жеid) под новым tenant и никого под старым;UPDATE staff_payroll_ledgerролью приложения по-прежнему отклоняется. - Повторный запуск (под
--fromпусто / у--toуже есть данные) — exit ≠ 0, ничего не меняет.
Что нужно учесть (видно по схеме, pg_policy/pg_constraint на PG17):
- У
staff_payroll_ledgerнет политики UPDATE/DELETE, у приложения нет права UPDATE, FORCE RLS действует и на владельца:krona_migratorстроки журнала не перенесёт. Нужна роль с обходом RLS (суперпользователь/BYPASSRLS) — поэтомуDATABASE_ADMIN_URL. - Внешние ключи составные
(tenant_id, …)и не DEFERRABLE: переносить родителя раньше детей нельзя — нужен порядок, отложенные проверки илиsession_replication_role = replicaв одной транзакции. - Политики INSERT
staff_audit_log,staff_payroll_ledger,staff_attendance_events,staff_timesheet_entriesтребуютactor_id/created_by/updated_by = current_setting('app.user_id')— для записи аудита без обхода RLS выставитьapp.user_id.
Расхождение с codex/fix-tenant-rehome (c73bb3b, 16:48 NOVT; ACCEPTANCE-3 с просьбой держаться C6 — 16:35).
Сценарий на ветке: dry-run exit: Tenant rehome stopped. Unknown option --from. По существу скрипт делает
всё, что проверяет сценарий (см. REPORT «Круг 3б»); не совпадает только интерфейс:
| C6 (сценарий) | c73bb3b |
Итог в сценарии |
|---|---|---|
--from, --to |
--source, --target |
Unknown option --from, exit 1 |
| без флага — перенос | нужен --apply, без режима — Specify --dry-run or --apply. |
— |
| — | --apply требует --actor <ULID> и --backup-evidence <json> |
у сценария нет ни того, ни другого |
--json |
неизвестный флаг → exit 1; JSON печатается всегда | — |
DATABASE_ADMIN_URL |
DATABASE_REHOME_URL (запасной вариант DATABASE_MIGRATION_URL) |
— |
| одна строка JSON, числа | многострочный JSON (JSON.stringify(…, null, 2)), счётчики — строки |
парсер сценария ищет JSON в последней строке |
ledger_amount_minor_sum в dry-run и apply |
в dry-run суммы нет; в apply payrollLedger: [{currency, amountMinor}] |
с адаптером: expected 'undefined' to be '328228' |
tables — строки у --from |
в apply tables — у --to после переноса (staff_audit_log +1) |
не проверяется |
Какой интерфейс оставить, решает владелец. Варианты: (а) Codex добавляет в скрипт C6-совместимые
--from/--to/--json, DATABASE_ADMIN_URL, сумму журнала в dry-run, а --actor/--backup-evidence
берёт из переменных окружения (например, REHOME_ACTOR_ID, REHOME_BACKUP_EVIDENCE); (б) владелец утверждает
интерфейс c73bb3b — тогда я меняю сценарий под него отдельным коммитом, а сумму журнала в dry-run
оставляю требованием (TASK-GROK-3 §4 п.3: «--dry-run — ничего не меняет, печатает те же числа», то есть числа п.2, включая SUM(amount_minor)). В TASK-CODEX-2 §2.2 п.4 dry-run
описан как «только отчёт о количестве строк по таблицам», то есть по этому пункту c73bb3b задание
выполняет, а расходится только с C6.
2. Дефекты продукта, найденные сценариями (все красные сейчас)
Команда и фактический вывод — tests/e2e/evidence/e2e-run.txt; таблица — tests/e2e/REPORT.md.
| ID | Файл | Что исправить |
|---|---|---|
| K4/N1 | src/portal.ts POST /employees |
42P08 inconsistent types deduced for parameter $2: явные $2::varchar(26), $5::text или отдельный запрос профессии |
| K3/N2 | src/portal.ts PATCH /work-sessions, src/domain/payroll/service.ts calculate/approve |
staff_outbox.occurred_at NULL (23502): передавать occurred_at или DEFAULT now() новой миграцией |
| K5/N4 | service.ts |
после N2 проверить: пересекающийся период не должен начислять смену повторно (409 или исключение уже начисленных смен) |
| K12/N3 | push-подписки | allowlist push-сервисов / запрет приватных адресов, redirect:'manual'; сейчас сервер подключается к 127.0.0.1 |
| N9 | push-dispatcher.ts |
ON CONFLICT ... DO UPDATE SET employee_id → 409 для чужого endpoint |
| N10 | GET /professions, /org-units | требовать право справочника; терминал сейчас получает 200 |
| N11 | импорт | валидировать kind и схему items → 400 вместо 500 (23514) |
| N12 | PUT pay-assignment | additionalProperties:false, верхние границы сумм |
| N12-DATE | POST /payroll/calculate |
month=2026-13 → 500 22008; проверять месяц 01–12 → 400 (диапазон 2026-02-30 уже даёт 400) |
| K6/D5 | portal.ts PATCH /work-sessions |
смена подписанной ведомости: 409, либо сторно в ledger; сейчас (на fix-live-database) 200 и начисление остаётся |
| K7/D2 | operations.ts импорт payroll_entries |
дельта по сумме всех записей дня, вставка по ключу: две точки за день → 222,00 вместо 333,00 ₽; считать дельту по ключу |
| K8/D1 | расчёт/подпись | снимок правил и ставок в подписанной ведомости; контракт проверки C4 (ниже) |
| K9/D3 | PUT pay-assignment | сохранять params по param_declarations правила (C5 ниже); сейчас shift_rate_minor официанта теряется |
| S9 | миграция 0011 FK устройств | ON DELETE SET NULL на составном (tenant_id, org_unit_id) обнуляет tenant_id → 23502; SET NULL (org_unit_id) или RESTRICT |
| A4 | обработчик ошибок | в теле 5xx нет SQLSTATE (code) и текста PostgreSQL; подробности только в лог |
| K1/F2 | config.ts/identity.ts |
standalone без токенов не должен выдавать права (процесс без токенов отдаёт 200 на /portal, /payroll, POST /professions) |
| K10/F3 | POST/DELETE /session | в cookie — идентификатор сессии, а не сырой токен; logout отзывает сессию |
| K11/F4 | вход | rate limit (тест ждёт 429 не позже 30 неверных попыток; идёт на отдельном процессе, чтобы лимит не мешал другим сценариям) |
| F7 | POST /attendance/events | использовать Idempotency-Key / staff_idempotency_keys |
| F10 | assertSameOrigin |
мутации по cookie без Origin отклонять |
| K13/SYNC-A, K13/SYNC-B | src/domain/sync/service.ts |
устройство не должно выставлять confirmed/approved (сейчас applied) |
| SYNC-C0 | pull() bootstrap |
SELECT ... status FROM staff_org_units — такого столбца нет → 500 на любой начальной загрузке |
| S5/SYNC-C | pull() bootstrap |
при has_more=true отдаётся next_cursor=latest, остаток после 100 сущностей теряется; нужен курсор снимка |
| S5/SYNC-D | портал/импорт | изменения вне sync не пишутся в staff_sync_change_log → терминал не узнаёт о новых/изменённых сотрудниках |
| S4/SYNC-E | executeCommand |
проверять status='active' сотрудника |
| S4/SYNC-F | executeCommand |
сохранять org_unit_id в staff_attendance_events; payload не может переопределить точку устройства |
| S3/SYNC-G | push() |
ошибки БД одной команды → rejected для неё, а не 500 и откат всего пакета |
| S8/SYNC-H | /sync/devices |
assertCookieMutationOrigin как в портале |
| K1/SYNC-I | requireManagerContext |
без токенов не выдавать права (как F2) |
| S2/SYNC-J | executeCommand |
окно времени отметки как в POST /attendance/events (−180 дней … +5 мин) |
| SYNC-K | acknowledge() |
отклонять курсор больше MAX(cursor_seq) |
3. deploy/ (K1/PILOT-1, K2/PILOT-2) — Codex
- PILOT-1: все подстановки в
deploy/pilot/compose.yaml→${VAR:?VAR is required}(сейчас 14 без:?: пустойSTANDALONE_MANAGER_TOKENмолча превращает pilot в F2). - PILOT-2:
NODE_ENV: developmentвapp. Конфликт:config.tsзапрещаетSTAFF_RUNTIME_MODE=standaloneприNODE_ENV=production. Нужно решение: либо разрешить standalone в production при обязательных токенах и HTTPS, либо отдельный режим для pilot. Тест требует только «не development». - N6:
scripts/create-app-role.mjsне работает мигратором без SUPERUSER («Only roles with SUPERUSER may change the SUPERUSER attribute»). CI и e2e обходятсяscripts/test/provision-pg.mjs(роли создаёт bootstrap-админ, какdocker/postgres/init-app-role.sh). В pilot мигратор =POSTGRES_USER= суперпользователь; рекомендую схему как в provision-pg.mjs.
4. CI
- Задаче
docker-buildнужен раннер с меткойdocker-host(Docker daemon). Без него задача ждёт в очереди; остальные задачи не блокируются. formatкрасная, пока не исправлен F14 (23 файла на замер 2026-09-26, в основномsrc/,docs/,tests/unit/).formatстанет зелёной после влитияcodex/fix-format-baseline(проверено на ветке).- Задача
windowsвыключена, пока нет раннера с меткойwindows: включается переменной репозиторияKRONA_WINDOWS_RUNNER=true; для полного e2e нужен секретWINDOWS_E2E_PG_ADMIN_URL(локальная PostgreSQL 17 на раннере). tests/e2e/evidence/не хранится в git; в CI это артефактe2e-evidence.- Реальный Forgejo-раннер мной не запускался (нет API-токена) — не проверено.
5. N13 (гонка первого расчёта) и утечка текста ошибок БД
scripts/test/n13-race.mjs, выводtests/e2e/evidence/n13-race.txt: 10/25/50 параллельных первыхPOST /payroll/calculate× 5 попыток. Как есть — все 500 (N2), гонку не видно. В одноразовой БД с обходом N2 (DEFAULT now()только там) — 0 из 30 некорректных попыток (без смен и с подтверждённой сменой): одинrun_id, один расчёт в БД.- Почему не воспроизводится (вывод из кода, не проверено отдельным экспериментом):
calculatePayrollсначала вызываетensureDefaultPayRules, а тамINSERT ... ON CONFLICT DO UPDATEпо одним и тем же строкамstaff_pay_rulesтенанта. Первая транзакция держит блокировки этих строк до коммита, остальные ждут — расчёты одного тенанта выполняются по очереди случайно. Если upsert правил вынесут из расчёта или сделаютDO NOTHING, окноSELECT ... FOR UPDATE(строки нет) →INSERT ... ON CONFLICT DO NOTHINGсо своимrunId→ строки/UPDATE по несуществующемуrunIdвернётся. Рекомендация: явныйpg_advisory_xact_lockпо (tenant, org_unit, period_start) илиINSERT ... ON CONFLICT DO UPDATE ... RETURNING id. Скрипт стоит перезапустить после такого изменения. - Ответы 500 содержат сырой текст ошибки PostgreSQL (например
null value in column "occurred_at" of relation "staff_outbox" ...) — клиенту видна схема БД. Для 5xx отдавать нейтральное сообщение, подробности — только в лог.
6. Приёмка веток исполнителей (2026-09-26)
Подробно — tests/e2e/REPORT.md и tests/e2e/report-evidence/acceptance-*.txt.
codex/fix-live-database(ea68e12, перепроверено наb289dd6): K3/N2 и K4/N1 зелёные на живой PostgreSQL 17. Дальше по цепочке открылись K5/N4 (196800 вместо 98400 — двойное начисление) и K6/D5 (отклонение оплаченной смены: 200, начисление осталось). A4 частично:POST /employeesбольше не 500, ноmonth=2026-13по-прежнему отдаётcode=22008с текстом.codex/fix-format-baseline(fd1ec3d):prettier --check .чистый. Но коммит «style» содержит функциональное исправление Antigravity:src/domain/sync/service.tsиtests/unit/sync.test.tsпосле нормализации prettier совпадают сantigravity/fix-reject-device-shifts(0 строк diff) и отличаются от331e490на 255/139 строк. Изменение поведения стоит вынести в отдельный коммит с объяснением или влить ветку Antigravity отдельно, иначе история смешивает темы (AGENTS.md).antigravity/fix-reject-device-shifts(795bba0, перепроверено на1df2019— уже наf5ac179): K13/SYNC-A и K13/SYNC-B зелёные, остальное без изменений.- Ни одна ветка не влита в основную (
f5ac179), поэтому ID изknown-defects.jsonне удалены. - Суммы в тестах кратны рублю: расчёт округляет строку до
rounding_unit_minor(по умолчанию 100 коп.). Если округление должно быть другим — это решение продукта, не теста.
7. Круг 3 (TASK-GROK-3, 2026-09-26)
Команды и полный вывод — tests/e2e/REPORT.md («Круг 3») и tests/e2e/report-evidence/round3-*.md.
Приёмка одной командой: node scripts/test/accept-branch.mjs <ветка>… (нужен E2E_PG_ADMIN_URL
или готовые роли в E2E_MIGRATOR_URL + E2E_APP_URL).
- Antigravity,
sync-bootstrap.test.ts(8baad55):Error: Called end on pool more than onceприTests 2 passed. Причина:app.close()в тесте вызывает хукonClose→database.close()(src/app.ts:148), затемafterAllзакрывает тот жеDatabaseещё раз. На текущей голове24cc18dфайл зелёный (1 passed (1) | 2 passed (2)). - Antigravity,
sync-rejection.test.ts(1df2019):column "created_by" of relation "staff_employees" does not existвbeforeAll(Tests 2 skipped). На6c5bf36/b283736исправлено. - Конфликты: на прежних головах
1df2019 × 8baad55и8baad55 × 513cdffконфликтовали вsrc/domain/sync/service.ts; на текущих головах (fetch 16:16 NOVT) конфликтов нет ни в одной из 55 пар. - Codex,
codex/fix-format-baseline: на513cdffвservice.ts/sync.test.tsбыло 232/130 строк сверх prettier, все есть вantigravity/fix-reject-device-shifts; наa05777c— только форматирование (19 файлов). - Codex,
live-postgres-remediation.test.ts: выполняется только приDATABASE_TEST_ISOLATED=true,DATABASE_TEST_GUARD_TOKEN, таблицеkrona_staff_test_guardс этим маркером и имени БДkrona_staff_audit_*. Соглашение нигде, кроме самого теста, не описано, и ни CI, ниscripts/test/*его не выполняют — вnpm run checkфайл всегдаskipped.accept-branchставит предохранитель в одноразовой БД:1 passed (1). Предложение: описать соглашение в README/AGENTS и после слияния включить его в CI (могу сделать в своей зоне,.forgejo/workflows/ci.yml). - N5 до сих пор в основе:
tenant-isolation.test.tsкрасный наb0243d5и всех ветках отf5ac179(permission denied for table staff_employees); исправление — вgrok/e2e-harness. Локальная сборка основа + fix-live-database + fix-sync-c0-bootstrap + grok/e2e-harness: интеграционные 7/7, храповик просит убрать ровно K3/N2, K4/N1, K13/SYNC-A, K13/SYNC-B, SYNC-C0. - Схема (низкий приоритет):
staff_notification_deliveries.outbox_id → staff_outbox(id)— единственный внешний ключ безtenant_id; все остальные составные(tenant_id, …). База не мешает доставке ссылаться на событие outbox другого арендатора (RLS фильтрует чтение, но не ссылку). Предложение:UNIQUE (tenant_id, id)наstaff_outboxи FK(tenant_id, outbox_id). - PILOT-REHOME: скрипта нет →
[PILOT-REHOME]красный; контракт — C6.
8. Круг 3б (основа f7d3c73, 2026-09-26 ~17:00 NOVT)
Вывод — tests/e2e/report-evidence/round3-accept-f7d3c73.md, round3-k18-and-rehome.md.
- codex/fix-tenant-config (
535052e):npm run checkкрасный —tests/unit/sync.test.ts:556:18→STANDALONE_TENANT_ID uses the development placeholder…(строка 553 — заглушка, 563 —NODE_ENV: 'test'). Вывод владельца подтверждён; как исправить — ACCEPTANCE-3 (разрешить заглушку приNODE_ENV === 'test'). - codex/fix-tenant-rehome (
c73bb3b): по существу перенос верный (копия после восстановления: счётчики, ledger, FK, аудитtenant.rehomed, изоляция, отказ повтора).[PILOT-REHOME]красный из-за интерфейса — таблица различий в C6. Интеграционный тестrehome-tenant.test.tsзелёный только сDATABASE_REHOME_TEST_URL/DATABASE_REHOME_TEST_CONFIRM— вnpm run checkи CI он всегдаskipped. Тест требует подключения суперпользователя (rehome-tenant.test.ts:92-93) и содержит одинit— запуск скрипта от не-суперпользователя (какkrona_migratorв пилоте) не покрыт. - codex/fix-pilot-backups (
a005c5e, K18):test-backup.sh/test-backup-pull.shпроходят (моки), но вnpm run checkи CI не входят. Учебное восстановление без Docker прошло (шим docker → pg_dump PG17, CMS, sha256, pg_restore,restore-drill-report.sqlсовпал). Замечания:backup.shснимает толькоpg_dump -Fcодной БД: ролей (globals) в копии нет. В кластере без ролейpg_restore→ exit 1, 61 ошибкаrole "krona_migrator" does not exist. Шаг 4 runbook («Restore required roles and grants») нужно сделать исполнимым: скрипт создания ролей для восстановления илиpg_dumpall --globals-only --no-role-passwordsрядом с копией.restore-drill-isolation.sqlжёстко зашит на01J00000000000000000000000→01M2R6AC5652NPT3MG34DKN4ZP; после переноса «source/target» поменяются местами — стоит параметризовать (psql -v).- В
docs/BACKUP-RESTORE.mdличный путьC:/Users/trush/Documents/KronaStaffBackups/— в репозитории лучше указать роль или место без имени пользователя. - Ротации копий нет (сказано в документе); отказ таймера/pull должен кто-то мониторить — это пока только текст.
- Предложение (моя зона, после слияния): добавить в CI
bash scripts/test-backup.sh,bash scripts/test-backup-pull.shи запускrehome-tenant.test.ts/live-postgres-remediation.test.tsна одноразовых БД — так же, как это делаетaccept-branch.