75 lines
8.5 KiB
Markdown
75 lines
8.5 KiB
Markdown
---
|
||
title: "sched F&F r8 — стенд верификации (schedule-as-entity)"
|
||
type: concept
|
||
tags: [sched, fnf, verification, stand, verdaccio, schedule-as-entity, docker]
|
||
sources: []
|
||
related: [concepts/windows-docker-test-harness-gotchas.md]
|
||
updated: 2026-08-18
|
||
---
|
||
|
||
# sched F&F r8 — стенд верификации
|
||
|
||
Кросс-агентный цикл F&F (findings & fixes): sched-команда публикует пакеты в
|
||
verdaccio, admin-сессия верифицирует на стенде и репортит находки через
|
||
инбокс (`sched/.agents/inbox/`). Раунд r8 = «schedule-as-entity» (движок тикает
|
||
по schedule-строкам). Цикл идёт письмами: intro → отчёт → фикс → перепроверка →
|
||
следующий пункт.
|
||
|
||
## Стенд
|
||
|
||
- Путь: `C:\Users\vitya\projects\.admin\.tmp\sched-r8\` (gitignored, живёт на диске).
|
||
- package.json: **@sched/core 0.40.2 / daemon 0.3.0 / storage-{mysql,postgres,mongo} 0.3.1 / ui 0.2.0** из verdaccio (`npm install --registry=https://verdaccio.kzntsv.site/`). `legacy/` — старый core 0.35.1 для генерации v0.6-БД.
|
||
- Docker-контейнеры (как в CI sched): `sched-mysql-test` :3308, `sched-mariadb-test` :3307, `sched-postgres-test` :5433, `sched-mongo-test` :27017; root:test / postgres:test.
|
||
|
||
## Репро-скрипты (15 шт., `.tmp/sched-r8/*.mjs`)
|
||
|
||
**Миграции / адаптеры (№1):**
|
||
- `migration-test.mjs` — sqlite v0.6→v0.7 (эталон синтеза)
|
||
- `adapter-migration-test.mjs` — F2: mysql/pg v3→v5, синтез легаси-строки, due стреляет
|
||
- `mongo-synthesis-test.mjs` — F2 mongo: first-open синтез, no-dup, non-empty gate. Легаси-док: коллекция `sched_tasks`, `config.data` (не `data`), `paused`/`disabled` обязательны (иначе null → не в due)
|
||
- `priority-order-test.mjs` — F1: task priority 10 наследуется на строку
|
||
- `adapters-spotcheck.mjs` — 12/12 CRUD+dedupKey-upsert на 4 адаптерах
|
||
- `tasks-json-test.mjs` — модель tasks.json (schedules:[...], fail-fast legacy key)
|
||
- `contract-parity.test.mjs` — vitest contract-сьют 5 адаптеров (см. гочу №2)
|
||
|
||
**Движок (№2, 75 проверок):**
|
||
- `engine-runs-test.mjs` (16) — scheduleId/data/trigger на schedule-ранах; manual (null+дефолты); retryRun (снапшот+retryOf)
|
||
- `engine-due-claim-test.mjs` (10) — priority-порядок, ceiling с блокирующим раннером, pause, once, catch-up
|
||
- `engine-retry-test.mjs` (27) — ретраи на строках (retryCount/backoff×multiplier/failCount/onRunFinal), override, retryOf-цепочка
|
||
- `engine-watchdog-test.mjs` (14) — reap обоих наборов локов, heartbeat real-clock, recoverOrphanRuns
|
||
- `engine-async-test.mjs` (8) — async poll через schedule-раны, poll timeout
|
||
|
||
**Политики (№3, 21 проверка):**
|
||
- `engine-policy-test.mjs` — whole-no-merge (override не наследует поля дефолта), snapshot-семантика пендинг-ретрая, pause AND два уровня, manual=дефолты задачи, priority-микс
|
||
|
||
**Admin API (№4, 52 проверки):**
|
||
- `admin-api-test.mjs` — живьём по HTTP против `createAdminApi` (in-process, listen(0), fetch): POST /schedules dedupKey-upsert 201/200 (UUID id, fileManaged=false, sync не дизаблит), tz ?? task.tz, GET /schedules first-class + lastRunStatus + effectiveStatus (no N+1 — ровно 3 чтения через счётчик storage-методов), GET/DELETE /:id (раны переживают delete), pause/resume (гейтит только строку), hard cut POST /tasks/:name/schedule → 404 с указателем, POST /tasks runtime (fileManaged=false, переживает sync, state сохраняется), PATCH merge, MCP list_schedules (runTool → новая форма).
|
||
|
||
**UI (№5, 13/13 зелёных + U1/U2):**
|
||
- `ui-backend.mjs` — бэкенд :8080 (createAdminApi, монтируется на /api/* как daemon — sched-ui serve проксирует путь verbatim), датасет books-паттерна: 4 строки × (active/failed, paused-schedule/succeeded, paused-task/без ранов, runtime-строка) + auth по SCHED_ADMIN_KEY.
|
||
- `sched-ui serve --proxy http://127.0.0.1:8080 --port 8081` + **браузерный CDP-стенд** (`~/projects/.common/scripts/browser/{start,nav,eval,screenshot}.js`): рендер таблицы (shadowRoot-инспекция), клики по форме create/edit/delete, перехват window.fetch для проверки body POST/PATCH/DELETE, мок window.confirm для delete, замер геометрии (getBoundingClientRect).
|
||
|
||
## Что подтверждено (контракт)
|
||
|
||
- **Ceiling сериализует через тики**: две due-строки одной задачи стреляют в РАЗНЫХ тиках (sibling-claim отклоняется атомарно). Параллелизм только между задачами.
|
||
- **onRunFinal** — на любом терминальном ране (успех тоже), не только на persistent-failure; «алерты только на фейлы» — фильтр consumer'а.
|
||
- **retryCount на строке** = consumed-попытки (кумулятив: после 2 фейлов = 2).
|
||
- **resolveSchedulePolicy** = `schedule.retry ?? task.retry` целиком; explicit `priority: 0` уважается как есть.
|
||
- **Snapshot-семантика**: правка политики не пересчитывает дедлайн пендинг-ретрая; свежая политика — со следующего диспатча.
|
||
- **pause AND**: `task.paused` гейтит все расписания (движок), `schedule.paused` — одно (due-запрос).
|
||
- **manual triggerTask** = дефолты задачи (data, без schedule-политики), расписание не двигается.
|
||
- **F1 (core 0.40.2)**: inner cron timezone ХОСТИТСЯ (`schedules.timezone ?? task/API tz ?? UTC`), конфликт-правило удалено — задача с tz может использовать другой inner timezone (доки были правы, код врал).
|
||
- **F3 (core 0.40.2)**: PATCH /schedules/:id = partial merge (RFC 7396-стиль): меняются только поля в теле, явный `null` очищает, опущенное сохраняется — dedupKey не осиротевает при правке одного правила.
|
||
|
||
## Находки №5 (UI, ждут разбора)
|
||
|
||
- **U1**: форма sched-schedules кладёт значение tz-поля ВНУТРЬ schedule-entry как `timezone` (валидно только для cron), а не как body-level `tz` → interval/once с tz нельзя ни создать, ни отредактировать (400 «timezone is only valid on cron schedules»); edit любой interval-строки с body-tz сломан (форма предзаполняет tz из строки).
|
||
- **U2**: таблица sched-schedules переполняет контейнер на ~58px (1076 vs 1018 при длинных JSON в rule/data) — actions/delete за правым краем карточки. Общий стиль `table{width:100%}` + auto-layout без `table-layout:fixed`/`word-break` на td; `overflow:hidden` на table не спасает. `sched-tasks` (7 колонок) — ровно 1018px.
|
||
|
||
## Как продолжить (закрытие раунда)
|
||
|
||
1. Бамп версий в package.json стенда → `npm install --registry=...` (после каждого фикса).
|
||
2. Новые проверки — отдельный `.mjs` по паттерну существующих (`check()` + SUMMARY), изолированные DB на сценарий; UI — браузерный CDP-стенд (см. выше).
|
||
3. Отчёт — письмо в `sched/.agents/inbox/` с фронтматтером `from: admin`, формат «делал → ожидал → получил → раздел доки». Не чинить, не пушить, их доску не трогать.
|
||
4. №1–№4 ПРИНЯТЫ (52/52 после фиксов), №5 репорт ушёл (13/13 + U1/U2) — ждём разбор → закрытие раунда (процедура fnf-testing-procedure пополнится результатами).
|