AURORA-1843: свод 2 — сценарии и скрипты замера страниц (3/3, стенд) #245

Open
aep wants to merge 12 commits from feat/236-aurora-1843-svod2-server-paging-perf into feat/236-aurora-1843-svod2-server-paging-web
Owner

Closes #236 (часть 3/3). Jira AURORA-1843 (эпик AURORA-1834). Стек: PR 1 (#241) → PR 2 (#243) → этот PR. Spec: openspec/changes/aurora-1843-svod2-server-paging/.

Что сделано (фаза 3 — стенд замеров; код стенда, сам стенд исполнителями не запускался)

  • perf/analysis/svod2_search_oracle.mjs --check и perf/analysis/svod2_paging_check.py: сверка страниц, поиска, фильтров, вариантов и компактной проекции с прежним полным ответом / экраном «до» на данных стенда.
  • perf/e2e/scenarios/scroll.spec.ts (только ветки svod2): first_rows_ms, json_bytes_sheet (прежний смысл), json_bytes_total, json_bytes_first, placeholder_frame_share, pages_requested, filter_result_ms; код работает и на сборке «до». Чистые помощники — perf/e2e/lib/svod2.ts.
  • perf/e2e/scenarios/svod2-memory.spec.ts: память GO «все» → RF «все» → GO.
  • api_split.py, explain_manual.py, scale_compare.py для страниц и вариантов свода 2; perf/README.md — раздел «Свод 2 после AURORA-1843» (порядок до/после, команды).

Тесты

  • node --test perf/analysis/svod2_search_oracle.test.mjs 13/13; node --test perf/e2e/tests/svod2-metrics.test.ts 10/10; pytest perf/tests (paging_check, svod2_analysis, analysis) 8/8; matchesSearch/equals в оракуле — дословные копии (MATCHES_OK, EQUALS_OK).
  • Не выполнялось (делает главный контроллер): проверка типов perf/e2e, npx playwright test --list, прогоны на стенде.

Команды замера

См. perf/README.md, раздел «Свод 2 после AURORA-1843» (порядок: «до» во временном worktree 1842 с подменой perf/ из этой ветки; перед «после» — svod2_paging_check.py и svod2_search_oracle.mjs --check).

Замер до/после — добавит контроллер после прогона на стенде.

Rulings I made

  • R-1 (design #35): Ruling: решения плана #23–#34 одобрены главным контроллером как есть — цена ошибки: нет.
  • R-2 (design #36): Ruling: хелпер legacy_full живёт в api/tests/integration/conftest.py (не в test_svod2_paging_api.py); Task 3 создаёт его там, Task 4 импортирует оттуда — иначе test_svod2_sql.py импортировал бы из тестового модуля. Цена ошибки: перенос функции.
  • R-3 (design #37): Ruling: проверки главного контроллера разделены: PG15.12 — я сам скриптом pg15check.sh <ветка> после снятия замка и пуша ветки; байт-в-байт на стенде, ручная проверка фазы 2, playwright --list/типы perf/e2e и замеры — главный контроллер, одним списком в финальном отчёте, не жду. Цена ошибки: нет.
  • R-4 (design #38): Ruling: в коммитах исполнителей трейлер Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> — как требуют план (Global Constraints) и WAVE2-RULES (явное указание человека приоритетнее общей подсказки). Цена ошибки: amend/rebase трейлера.
  • R-9 (design #43): Ruling: I-2 ревью Task 12 — единый источник высоты окна: измеряется реальная высота первой строки с данными (по умолчанию 37), используется в estimateSize/measureElement/rowHeight хука/padding; ROW_VIRTUALIZER_OPTIONS не правится. Причина: константа 37 при реальных ≈44 px даёт наложение строк (нарушение «визуально прежнее»). Цена: лишний рендер при первом измерении; ручная проверка контроллера на стенде.
  • R-10 (design #44): Ruling: T12.1 (окно запрашивается после первой страницы), T12.2 (запрос offset>=total при сужающем refine глубоко внизу — неизбежен, новый total заранее неизвестен), T12.4 (после ошибки смена поиска запускает refine вместо ожидания «Повторить»), T12.5 (заглушки на границе страниц после refine/«Обновить») — принимаются как осознанные отступления, deferred; проверка на стенде главным контроллером. Цена: лишний запрос/кратковременные заглушки.
  • R-11 (design #45): Ruling: сценарии стенда не засчитывают скелетоны как строки данных; O-7 (видимые пользователю скелетоны до конца загрузки окна) — решение за главным контроллером. Цена: нечестное «до/после» либо переделка loading на фронте.
  • R-5 (design #39): Ruling: I-1 финального ревью фазы 1 (стоимость серверного поиска) — deferred, не правим предикат без замера; цена: правка в 0053 до слияния, если замер даст недобор.
  • R-6 (design #40): Ruling: facets считает svod2_lines дважды (отклонение от design §4 из-за N² в коррелированном подзапросе) — цена: время facets с поиском.
  • R-7 (design #41): Ruling: значения поиска/фильтров не пишутся в лог db_time (M-2) — цена: нет.
  • R-8 (design #42): Ruling: M-4 (NUL в search → вероятно 5xx) deferred — цена: 5xx на искусственном запросе.

Находки (маркер, суть, статус)

Маркер Суть Статус
O-1 Перекрытие полей поиска: contract_summary перекрыто contract_detail при поиске на экране «до» (design «Найденные странности») deferred
O-2 Поиск по техническим id (design «Найденные странности») deferred
T1.1 NBSP/U+FEFF в SYNTHETIC_ROWS записаны сырыми символами (хрупко при форматировании) deferred
T1.2 SCREEN_CASES не ищет значения с NBSP/U+FEFF внутри deferred
T2.1 _JS_WHITESPACE сырыми невидимыми символами в svod2_oracle.py deferred
T2.2 расхождение Python lower() и JS toLowerCase не задокументировано в модуле deferred
T2.3 мёртвые ветки в js_number_text; OverflowError для огромных int deferred
T2.4 ключи фасетов без js_string (колонки строковые) deferred
T2.5 test_js_number_text_matches_node_vectors не параметризован deferred
T3.1 Эталон и порядок org_name зависят от collation БД (perf-pg): на PG15 контура golden-тест проверен rejected: прогон PG15.12 — эталон совпал, те же 3 падения
T3.2 svod2_seed.sql режется по ; — точка с запятой в тексте засева сломает скрипт deferred
T3.3 cd_id = expense_item_id (о��щий у нескольких строк), имя ключа вводит в заблуждение deferred
T3.4 добавлен фильтр search+type-hit (search+type из брифа даёт пусто) rejected: сохранены оба, это усиление
T3.5 / O-3 трейлер коммита b134cfd Sonnet 5.5 вместо Opus 5.5 (T1,T2 — Opus) deferred (документальное)
T4.1 тест trim не проверяет U+180E и U+0085 (не должны обрезаться) deferred
T4.2 casefold-тесты не покрывают весь U+0400–040F и Ø/İ deferred
T4.3 test_compact проверяет проекцию только на одной RF-строке deferred
T5.I-1 Important: коррелированный IN в v_svod2_facets (N^2) fixed e81df1d
T5.1 ELSE kv.value::text для object/array расходится с String(), но недостижимо (поля скалярные) deferred
T5.2 откат засева зависел от запроса к API fixed e81df1d
T5.3 "" и " " в тесте поиска передавались как NULL fixed e81df1d, f5bccc5
T5.4 фильтр из пробелов в SQL снимается NULLIF, в MRT не снимается (по design §3) rejected: решено в design §3
T5.5 EXISTS поиска заново соединяет таблицы вместо presence_*; header jsonb_build_object продублирован в трёх местах deferred (perf-фаза)
T5.6 test_facets_match_screen_oracle не передаёт " " (search or None) deferred
O-4 Исполнитель Task 5 в fix-раунде завёл собственного ревьюера (нарушение контракта «без сабагентов»); результат ревью не использован deferred (процесс)
T6.1 ORDER BY kind,value в facets-запросе по collation БД (клиент сортирует сам) deferred
T6.2 total по индексу result[0][4] вместо имени fixed 782a043 (= M-5)
T6.3 past-end второй вызов равен по цене первому deferred
T6.4 нет тестов на offset=None и пустой второй вызов deferred
T7.1 лог db_time пишет значения поиска/фильтров fixed 782a043 (= M-2)
T7.2 test_summary2_mode покрывает 4 комбинации из 32 deferred
T7.3 _parse_org_ids вызывается внутри веток, а не до ветвления deferred
I-1 Серверный поиск: ~1,46 с на 10 тыс. строк (translate-casefold, plpgsql числа); предложено регулярное выражение deferred (R-5, design #39; замер контроллера; закрывается вместе с T5.5)
M-1 нет теста перекрытия contract_summary пустой секцией (ооо лютик, дс-2) fixed 782a043
M-2 / T7.1 текст поиска/фильтров в логе db_time fixed 782a043
M-3 двойной svod2_lines в facets не в design.md fixed (design #40, docs-коммит)
M-4 NUL в search/фильтре → вероятно 5xx deferred (R-8, design #42)
M-5 / T6.2 total по индексу fixed 782a043
T10.1 EMPTY_FACET_MAP: Object.freeze(Map) не делает Map неизменяемым deferred (по брифу; не мутировать)
T10.2 getVisiblePage при rowHeight<=0 неявно безопасен deferred
T10.3 touchPage может оставить size>5, если все страницы в keepPages deferred (на практике ≤4)
T10.4 getSvod2RowId опирается на форму row.data.header deferred
T11.I-1 Important: begin(load) очищал pages/total/facets (расхождение с экраном «до») fixed 325c1c5
T11.I-2 Инвариант: хук обязан слать settled для каждого поколения (loading не залипает) fixed 325c1c5 (тест + комментарий; реализация в Task 12)
T11.1 fail(load/refine) не сбрасывает dataGeneration/loadedQueryKey (как «до») deferred
T11.2 отчёт исполнителя неверно цитирует бриф про «очищает» rejected: учтено в T11.I-1
O-5 Re-review Task 11 fix выполнен контроллером по диффу (1 строка), не отдельным ревьюером deferred (процесс)
T12.C-1 Critical: смена поиска/фильтра во время первой загрузки теряется fixed d74f528
T12.I-1 «Найдено N из M» рядом с ошибкой fixed d74f528
T12.I-2 ROW_HEIGHT=37 vs реальные ≈44 px, наложение строк fixed d74f528 (R-9; проверить измерение на стенде)
T12.1 окно запрашивается после ответа первой страницы deferred (R-10)
T12.2 запрос offset>=total при сужающем refine глубоко внизу deferred (R-10)
T12.3 варианты/«Найдено» на время загрузки показывают прежний запрос deferred
T12.4 после ошибки смена поиска запускает refine deferred (R-10)
T12.5 заглушки на границе страниц после refine/«Обновить» deferred (R-10)
T12.6 rowVirtualizerOptions пересоздаются каждый рендер; facetsMapRef пишется в рендере; load(mode) игнорирует mode; повтор при ошибке прокрутки на каждом кадре deferred
T12.7 нет тестов логики хука fixed частично d74f528 (чистая shouldRefine)
T12.8 измерение высоты ловило скелетон/«Нет данных» fixed fbc3601 (= I-2)
T12.9 высота определяется по строке 0; неоднородная высота fixed fbc3601 (максимум по отрисованным строкам, M-7); проверка на стенде
O-6 biome check Svod2Page.jsx: ошибка формата в строках scaleNumericColumns/, не наших (заявлено исполнителями; не подтверждено полностью) deferred
I-2 Important: высота строки (R-9) мерялась по скелетону при «Обновить» → пустой экран, потеря позиции fixed fbc3601
I-3 Important: возврат к ранее загруженным условиям (A→B→A) показывал строки по устаревшим поиску/фильтрам fixed fbc3601
M-6 заглушки ниже соседних строк (зазоры) fixed fbc3601
M-7 защита от зацикливания измерения высоты fixed fbc3601 (остаточно: значение не монотонно, не сбрасывается при смене условий)
M-8 syncWindow принимал страницы прежнего поколения fixed fbc3601
M-9 лишний refine на пробелы по краям поиска (refineKey из сырого search) deferred
T14.1 compare_stitched: ids.count O(n^2) deferred
T14.2 compare_stitched: строки без line_id считаются повторами deferred
T14.3 main перезапрашивает полный список для compact deferred
T14.4 страница за концом: total не проверяется deferred
T14.5 CLI --check: нет проверки обязательных аргументов deferred
T14.6 порядок импортов в тесте (biome organizeImports не запускался) deferred
T14.7 год/пользователь из sheets[0] без фильтра owner deferred (проверит контроллер на стенде)
T15.I-1 Important: filter_result_ms на «до» включал таймаут ожидания поиска 5 с fixed 5dc6662
T15.1 filter_result_ms на «после» может занижаться (stable до ответа) — учтено в filterResultMs (max) fixed 5dc6662
T15.2 pages_requested/json_bytes в записи фильтра включают исходную загрузку fixed 9272ea2
T15.3 signature() считает заглушки; filter_no_effect определяется по «Найдено» deferred
T15.4 rAF-сэмплер вносит одинаковую нагрузку в «до» и «после» rejected: одинаково для обеих сборок
T15.5 pages_requested на «до» = 0 — не сравнивать как число страниц fixed 9272ea2 (README, M-13)
T15.6 query разбирается вручную вместо URLSearchParams deferred
T16.C1 Critical: точка final в svod2-memory повторяла loadAll и снимала выбор «Все ССП/РФ» fixed 4e5ba53
T16.1 фиксированные 500 мс вместо ожидания стабилизации fixed 4e5ba53 (settle)
T16.2 waitRows неявно зависит от data=[] у незагруженной вкладки deferred
T16.3 rf_scrolled: MAX_STEPS может не дойти до конца на большом масштабе deferred (PERF_MAX_STEPS)
T16.4 нет attachNetlog в svod2-memory deferred
T17.1 ключи svod2_key «страница» не различают view=full/compact/search fixed 9272ea2
T17.2 docstring api_split не обновлён deferred
T17.3 /facets: колонка «строк ответа» считает ключи dict fixed 9272ea2
T17.4 трейлер коммита 558ad81 Haiku 5.5 вместо Opus 5.5 (см. O-3) deferred (документальное)
T17.5 имя ветки в конце perf/README.md не сверено rejected: проверено ревьюером, совпадает
I-4 Important: first_rows_ms/waitRows на «после» засчитывали строки-скелетоны (loading=true до settled) fixed 9272ea2
I-5 Important: README не описывал порядок до/после (checkout perf/ в worktree «до», stand.sh из своих worktree) fixed 9272ea2, 0f7c6c5
I-6 Important (ре-ревью): TimeoutError от waitForFunction ломал запись incomplete fixed 0f7c6c5
M-10 filter_result_ms на «после» не учитывает facets/остальные страницы deferred
M-11 first_rows_ms квантовался опросом 500 мс fixed 0f7c6c5 (raf-наблюдатель)
M-12 EXPLAIN v_svod2_go/rf (SET search_path) даёт один Function Scan без узлов deferred
M-13 README без списка новых метрик fixed 9272ea2
M-14 устаревший заголовок svod2-memory.spec.ts fixed 9272ea2
M-15 сверки идентифицируют строки по line_id (в GO не уникален); stitch_pages без защиты от бесконечного цикла deferred
O-7 UX фазы 2: в режиме load loading=true до settled → MRT рисует скелетоны в ячейках, пока не придут facets и страницы окна (на «до» строки сразу показывали данные). Допустимое «время ожидания», но отличие видно; проверить на стенде deferred (контроллеру)

🤖 Generated with Claude Code

Closes #236 (часть 3/3). Jira AURORA-1843 (эпик AURORA-1834). Стек: PR 1 (#241) → PR 2 (#243) → этот PR. Spec: `openspec/changes/aurora-1843-svod2-server-paging/`. ## Что сделано (фаза 3 — стенд замеров; код стенда, сам стенд исполнителями не запускался) - `perf/analysis/svod2_search_oracle.mjs --check` и `perf/analysis/svod2_paging_check.py`: сверка страниц, поиска, фильтров, вариантов и компактной проекции с прежним полным ответом / экраном «до» на данных стенда. - `perf/e2e/scenarios/scroll.spec.ts` (только ветки `svod2`): `first_rows_ms`, `json_bytes_sheet` (прежний смысл), `json_bytes_total`, `json_bytes_first`, `placeholder_frame_share`, `pages_requested`, `filter_result_ms`; код работает и на сборке «до». Чистые помощники — `perf/e2e/lib/svod2.ts`. - `perf/e2e/scenarios/svod2-memory.spec.ts`: память GO «все» → RF «все» → GO. - `api_split.py`, `explain_manual.py`, `scale_compare.py` для страниц и вариантов свода 2; `perf/README.md` — раздел «Свод 2 после AURORA-1843» (порядок до/после, команды). ## Тесты - `node --test perf/analysis/svod2_search_oracle.test.mjs` 13/13; `node --test perf/e2e/tests/svod2-metrics.test.ts` 10/10; pytest `perf/tests` (paging_check, svod2_analysis, analysis) 8/8; `matchesSearch`/`equals` в оракуле — дословные копии (MATCHES_OK, EQUALS_OK). - Не выполнялось (делает главный контроллер): проверка типов perf/e2e, `npx playwright test --list`, прогоны на стенде. ## Команды замера См. `perf/README.md`, раздел «Свод 2 после AURORA-1843» (порядок: «до» во временном worktree 1842 с подменой `perf/` из этой ветки; перед «после» — `svod2_paging_check.py` и `svod2_search_oracle.mjs --check`). Замер до/после — добавит контроллер после прогона на стенде. ## Rulings I made - R-1 (design #35): Ruling: решения плана #23–#34 одобрены главным контроллером как есть — цена ошибки: нет. - R-2 (design #36): Ruling: хелпер `legacy_full` живёт в `api/tests/integration/conftest.py` (не в test_svod2_paging_api.py); Task 3 создаёт его там, Task 4 импортирует оттуда — иначе test_svod2_sql.py импортировал бы из тестового модуля. Цена ошибки: перенос функции. - R-3 (design #37): Ruling: проверки главного контроллера разделены: PG15.12 — я сам скриптом pg15check.sh <ветка> после снятия замка и пуша ветки; байт-в-байт на стенде, ручная проверка фазы 2, `playwright --list`/типы perf/e2e и замеры — главный контроллер, одним списком в финальном отчёте, не жду. Цена ошибки: нет. - R-4 (design #38): Ruling: в коммитах исполнителей трейлер `Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>` — как требуют план (Global Constraints) и WAVE2-RULES (явное указание человека приоритетнее общей подсказки). Цена ошибки: amend/rebase трейлера. - R-9 (design #43): Ruling: I-2 ревью Task 12 — единый источник высоты окна: измеряется реальная высота первой строки с данными (по умолчанию 37), используется в estimateSize/measureElement/rowHeight хука/padding; ROW_VIRTUALIZER_OPTIONS не правится. Причина: константа 37 при реальных ≈44 px даёт наложение строк (нарушение «визуально прежнее»). Цена: лишний рендер при первом измерении; ручная проверка контроллера на стенде. - R-10 (design #44): Ruling: T12.1 (окно запрашивается после первой страницы), T12.2 (запрос offset>=total при сужающем refine глубоко внизу — неизбежен, новый total заранее неизвестен), T12.4 (после ошибки смена поиска запускает refine вместо ожидания «Повторить»), T12.5 (заглушки на границе страниц после refine/«Обновить») — принимаются как осознанные отступления, deferred; проверка на стенде главным контроллером. Цена: лишний запрос/кратковременные заглушки. - R-11 (design #45): Ruling: сценарии стенда не засчитывают скелетоны как строки данных; O-7 (видимые пользователю скелетоны до конца загрузки окна) — решение за главным контроллером. Цена: нечестное «до/после» либо переделка loading на фронте. - R-5 (design #39): Ruling: I-1 финального ревью фазы 1 (стоимость серверного поиска) — deferred, не правим предикат без замера; цена: правка в 0053 до слияния, если замер даст недобор. - R-6 (design #40): Ruling: facets считает svod2_lines дважды (отклонение от design §4 из-за N² в коррелированном подзапросе) — цена: время facets с поиском. - R-7 (design #41): Ruling: значения поиска/фильтров не пишутся в лог db_time (M-2) — цена: нет. - R-8 (design #42): Ruling: M-4 (NUL в search → вероятно 5xx) deferred — цена: 5xx на искусственном запросе. ## Находки (маркер, суть, статус) | Маркер | Суть | Статус | |---|---|---| | O-1 | Перекрытие полей поиска: contract_summary перекрыто contract_detail при поиске на экране «до» (design «Найденные странности») | deferred | | O-2 | Поиск по техническим id (design «Найденные странности») | deferred | | T1.1 | NBSP/U+FEFF в SYNTHETIC_ROWS записаны сырыми символами (хрупко при форматировании) | deferred | | T1.2 | SCREEN_CASES не ищет значения с NBSP/U+FEFF внутри | deferred | | T2.1 | _JS_WHITESPACE сырыми невидимыми символами в svod2_oracle.py | deferred | | T2.2 | расхождение Python lower() и JS toLowerCase не задокументировано в модуле | deferred | | T2.3 | мёртвые ветки в js_number_text; OverflowError для огромных int | deferred | | T2.4 | ключи фасетов без js_string (колонки строковые) | deferred | | T2.5 | test_js_number_text_matches_node_vectors не параметризован | deferred | | T3.1 | Эталон и порядок org_name зависят от collation БД (perf-pg): на PG15 контура golden-тест проверен | rejected: прогон PG15.12 — эталон совпал, те же 3 падения | | T3.2 | svod2_seed.sql режется по `;` — точка с запятой в тексте засева сломает скрипт | deferred | | T3.3 | cd_id = expense_item_id (о��щий у нескольких строк), имя ключа вводит в заблуждение | deferred | | T3.4 | добавлен фильтр search+type-hit (search+type из брифа даёт пусто) | rejected: сохранены оба, это усиление | | T3.5 / O-3 | трейлер коммита b134cfd Sonnet 5.5 вместо Opus 5.5 (T1,T2 — Opus) | deferred (документальное) | | T4.1 | тест trim не проверяет U+180E и U+0085 (не должны обрезаться) | deferred | | T4.2 | casefold-тесты не покрывают весь U+0400–040F и Ø/İ | deferred | | T4.3 | test_compact проверяет проекцию только на одной RF-строке | deferred | | T5.I-1 | Important: коррелированный IN в v_svod2_facets (N^2) | fixed e81df1d | | T5.1 | ELSE kv.value::text для object/array расходится с String(), но недостижимо (поля скалярные) | deferred | | T5.2 | откат засева зависел от запроса к API | fixed e81df1d | | T5.3 | "" и " " в тесте поиска передавались как NULL | fixed e81df1d, f5bccc5 | | T5.4 | фильтр из пробелов в SQL снимается NULLIF, в MRT не снимается (по design §3) | rejected: решено в design §3 | | T5.5 | EXISTS поиска заново соединяет таблицы вместо presence_*; header jsonb_build_object продублирован в трёх местах | deferred (perf-фаза) | | T5.6 | test_facets_match_screen_oracle не передаёт " " (search or None) | deferred | | O-4 | Исполнитель Task 5 в fix-раунде завёл собственного ревьюера (нарушение контракта «без сабагентов»); результат ревью не использован | deferred (процесс) | | T6.1 | ORDER BY kind,value в facets-запросе по collation БД (клиент сортирует сам) | deferred | | T6.2 | total по индексу result[0][4] вместо имени | fixed 782a043 (= M-5) | | T6.3 | past-end второй вызов равен по цене первому | deferred | | T6.4 | нет тестов на offset=None и пустой второй вызов | deferred | | T7.1 | лог db_time пишет значения поиска/фильтров | fixed 782a043 (= M-2) | | T7.2 | test_summary2_mode покрывает 4 комбинации из 32 | deferred | | T7.3 | _parse_org_ids вызывается внутри веток, а не до ветвления | deferred | | I-1 | Серверный поиск: ~1,46 с на 10 тыс. строк (translate-casefold, plpgsql числа); предложено регулярное выражение | deferred (R-5, design #39; замер контроллера; закрывается вместе с T5.5) | | M-1 | нет теста перекрытия contract_summary пустой секцией (ооо лютик, дс-2) | fixed 782a043 | | M-2 / T7.1 | текст поиска/фильтров в логе db_time | fixed 782a043 | | M-3 | двойной svod2_lines в facets не в design.md | fixed (design #40, docs-коммит) | | M-4 | NUL в search/фильтре → вероятно 5xx | deferred (R-8, design #42) | | M-5 / T6.2 | total по индексу | fixed 782a043 | | T10.1 | EMPTY_FACET_MAP: Object.freeze(Map) не делает Map неизменяемым | deferred (по брифу; не мутировать) | | T10.2 | getVisiblePage при rowHeight<=0 неявно безопасен | deferred | | T10.3 | touchPage может оставить size>5, если все страницы в keepPages | deferred (на практике ≤4) | | T10.4 | getSvod2RowId опирается на форму row.data.header | deferred | | T11.I-1 | Important: begin(load) очищал pages/total/facets (расхождение с экраном «до») | fixed 325c1c5 | | T11.I-2 | Инвариант: хук обязан слать settled для каждого поколения (loading не залипает) | fixed 325c1c5 (тест + комментарий; реализация в Task 12) | | T11.1 | fail(load/refine) не сбрасывает dataGeneration/loadedQueryKey (как «до») | deferred | | T11.2 | отчёт исполнителя неверно цитирует бриф про «очищает» | rejected: учтено в T11.I-1 | | O-5 | Re-review Task 11 fix выполнен контроллером по диффу (1 строка), не отдельным ревьюером | deferred (процесс) | | T12.C-1 | Critical: смена поиска/фильтра во время первой загрузки теряется | fixed d74f528 | | T12.I-1 | «Найдено N из M» рядом с ошибкой | fixed d74f528 | | T12.I-2 | ROW_HEIGHT=37 vs реальные ≈44 px, наложение строк | fixed d74f528 (R-9; проверить измерение на стенде) | | T12.1 | окно запрашивается после ответа первой страницы | deferred (R-10) | | T12.2 | запрос offset>=total при сужающем refine глубоко внизу | deferred (R-10) | | T12.3 | варианты/«Найдено» на время загрузки показывают прежний запрос | deferred | | T12.4 | после ошибки смена поиска запускает refine | deferred (R-10) | | T12.5 | заглушки на границе страниц после refine/«Обновить» | deferred (R-10) | | T12.6 | rowVirtualizerOptions пересоздаются каждый рендер; facetsMapRef пишется в рендере; load(mode) игнорирует mode; повтор при ошибке прокрутки на каждом кадре | deferred | | T12.7 | нет тестов логики хука | fixed частично d74f528 (чистая shouldRefine) | | T12.8 | измерение высоты ловило скелетон/«Нет данных» | fixed fbc3601 (= I-2) | | T12.9 | высота определяется по строке 0; неоднородная высота | fixed fbc3601 (максимум по отрисованным строкам, M-7); проверка на стенде | | O-6 | biome check Svod2Page.jsx: ошибка формата в строках scaleNumericColumns/<Tab>, не наших (заявлено исполнителями; не подтверждено полностью) | deferred | | I-2 | Important: высота строки (R-9) мерялась по скелетону при «Обновить» → пустой экран, потеря позиции | fixed fbc3601 | | I-3 | Important: возврат к ранее загруженным условиям (A→B→A) показывал строки по устаревшим поиску/фильтрам | fixed fbc3601 | | M-6 | заглушки ниже соседних строк (зазоры) | fixed fbc3601 | | M-7 | защита от зацикливания измерения высоты | fixed fbc3601 (остаточно: значение не монотонно, не сбрасывается при смене условий) | | M-8 | syncWindow принимал страницы прежнего поколения | fixed fbc3601 | | M-9 | лишний refine на пробелы по краям поиска (refineKey из сырого search) | deferred | | T14.1 | compare_stitched: ids.count O(n^2) | deferred | | T14.2 | compare_stitched: строки без line_id считаются повторами | deferred | | T14.3 | main перезапрашивает полный список для compact | deferred | | T14.4 | страница за концом: total не проверяется | deferred | | T14.5 | CLI --check: нет проверки обязательных аргументов | deferred | | T14.6 | порядок импортов в тесте (biome organizeImports не запускался) | deferred | | T14.7 | год/пользователь из sheets[0] без фильтра owner | deferred (проверит контроллер на стенде) | | T15.I-1 | Important: filter_result_ms на «до» включал таймаут ожидания поиска 5 с | fixed 5dc6662 | | T15.1 | filter_result_ms на «после» может занижаться (stable до ответа) — учтено в filterResultMs (max) | fixed 5dc6662 | | T15.2 | pages_requested/json_bytes в записи фильтра включают исходную загрузку | fixed 9272ea2 | | T15.3 | signature() считает заглушки; filter_no_effect определяется по «Найдено» | deferred | | T15.4 | rAF-сэмплер вносит одинаковую нагрузку в «до» и «после» | rejected: одинаково для обеих сборок | | T15.5 | pages_requested на «до» = 0 — не сравнивать как число страниц | fixed 9272ea2 (README, M-13) | | T15.6 | query разбирается вручную вместо URLSearchParams | deferred | | T16.C1 | Critical: точка final в svod2-memory повторяла loadAll и снимала выбор «Все ССП/РФ» | fixed 4e5ba53 | | T16.1 | фиксированные 500 мс вместо ожидания стабилизации | fixed 4e5ba53 (settle) | | T16.2 | waitRows неявно зависит от data=[] у незагруженной вкладки | deferred | | T16.3 | rf_scrolled: MAX_STEPS может не дойти до конца на большом масштабе | deferred (PERF_MAX_STEPS) | | T16.4 | нет attachNetlog в svod2-memory | deferred | | T17.1 | ключи svod2_key «страница» не различают view=full/compact/search | fixed 9272ea2 | | T17.2 | docstring api_split не обновлён | deferred | | T17.3 | /facets: колонка «строк ответа» считает ключи dict | fixed 9272ea2 | | T17.4 | трейлер коммита 558ad81 Haiku 5.5 вместо Opus 5.5 (см. O-3) | deferred (документальное) | | T17.5 | имя ветки в конце perf/README.md не сверено | rejected: проверено ревьюером, совпадает | | I-4 | Important: first_rows_ms/waitRows на «после» засчитывали строки-скелетоны (loading=true до settled) | fixed 9272ea2 | | I-5 | Important: README не описывал порядок до/после (checkout perf/ в worktree «до», stand.sh из своих worktree) | fixed 9272ea2, 0f7c6c5 | | I-6 | Important (ре-ревью): TimeoutError от waitForFunction ломал запись incomplete | fixed 0f7c6c5 | | M-10 | filter_result_ms на «после» не учитывает facets/остальные страницы | deferred | | M-11 | first_rows_ms квантовался опросом 500 мс | fixed 0f7c6c5 (raf-наблюдатель) | | M-12 | EXPLAIN v_svod2_go/rf (SET search_path) даёт один Function Scan без узлов | deferred | | M-13 | README без списка новых метрик | fixed 9272ea2 | | M-14 | устаревший заголовок svod2-memory.spec.ts | fixed 9272ea2 | | M-15 | сверки идентифицируют строки по line_id (в GO не уникален); stitch_pages без защиты от бесконечного цикла | deferred | | O-7 | UX фазы 2: в режиме load loading=true до settled → MRT рисует скелетоны в ячейках, пока не придут facets и страницы окна (на «до» строки сразу показывали данные). Допустимое «время ожидания», но отличие видно; проверить на стенде | deferred (контроллеру) | 🤖 Generated with [Claude Code](https://claude.com/claude-code)
aep added 9 commits 2026-10-28 23:49:26 +03:00
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
api_split: GO/RF полный и compact ответ страницей 300, /facets, RF compact с поиском.
explain_manual: svod2_go_page, svod2_rf_page, svod2_rf_search, svod2_go_facets
(год из манифеста). scale_compare: svod2_key разводит полный ответ, страницу и facets.
README: раздел «Свод 2 после AURORA-1843» (порядок до/после, сверка, команды, --only/--repeats).
Тесты: perf/tests/test_svod2_analysis.py.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Селектор строк данных свода 2 исключает скелетоны MRT, settle ждёт 0 скелетонов;
first_rows_ms через waitForFunction(raf); счётчики загрузки не пишутся в запись фильтра;
scale_compare различает view/search; api_split не считает строки для facets;
README: порядок до/после и новые метрики.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Author
Owner

Ночной замер — часть 2 (итог)

Сборки: «до» — вершина 1842 399234a с perf/ из этой ветки (git checkout … -- perf/, без коммита), «после» — 3e9979d. Масштаб 1 (D0) и 2 (D2). Прогон по perf/README.md «Свод 2 после AURORA-1843» и списку «Проверки для главного контроллера».

Проверки инструмента

проверка результат
PERF_SQLSTATS=0 npx playwright test --list Total: 396 tests in 10 files, ошибок загрузки нет
tsc (perf/e2e) rc=1: lib/manifest.ts(32,51): TS2783 'owner' is specified more than once, so this usage will be overwritten. Строка 32 ({ owner: 'rf', ...s }) идентична в origin/test, 1842 (399234a) и этой ветке (3e9979d); файл не менялся ни в 1842, ни в 1843: ошибка пришла из PR «каркас замеров фронта» (#203), не из 1843. На вершине 1842 tsc отдельно не запускался — вывод по тексту исходников
svod2_paging_check.py, масштаб 1 / масштаб 2 CHECK_OK (GO 5 617 / RF 8 597 строк; масштаб 2: 22 419 / 34 644; расхождений 0)
svod2_search_oracle.mjs --check, масштаб 1 / 2 CHECK_OK / CHECK_OK

Что в прогоне вышло с rc≠0 и почему

  • «before split rc=1» (03:20): api_split.py из этой ветки запрашивает /svod/2/GO/2026/facets, на сервере 1842 его нет — HTTP 404. Переснято инструментом 1842 (perf/ без правок PR 3): rc=0 (04:11), «до» в #241 взято оттуда. Аналогично «before explain rc=1» (нет функции v_svod2_go с новой сигнатурой) → переснято 04:11.
  • Фильтр GO (--grep filter): «filter did not stabilize in 120s» и на «до», и на «после» (logs/1843-{before,after}-filter.log), метрик нет; RF-фильтр отработал: 432 → 857 мс.
  • Первый прогон phase2 (before/after): клики по select-фильтрам — тайм-аут 30 с (локатор) → в before2/after2 исправлено и повторено.

Цели design (масштаб 1)

метрика цель факт
память final ≤ 0.30× 0.073× (586.8 → 42.6 МБ) выполнено
first_rows_ms ≤ 0.5× 0.36× / 0.28× (GO / RF) выполнено
compact / full ≤ 0.40 0.15 / 0.14 выполнено
первая страница + facets ≤ 5 % 1.6 % / 1.0 % выполнено
прежний запрос ≤ 1.10× 1.06× / 1.05× выполнено
шаг прокрутки ≤ 1.10× 0.90× / 0.86× выполнено
placeholder_frame_share ≤ 5 % 0 выполнено формально (см. O-7 в #243)
память s2 ≤ 1.25× «после» s1 не снято
Не снято: память и прокрутка на масштабе 2 (на s2 снимались только gen/verify, api_split, paging_check, oracle, время поиска; фаза 5 закончилась в 05:37).
Время серверного поиска (I-1) и O-7 — см. #241 и #243.
Файлы: /private/tmp/claude-501/-Users-andrey-epifancev-projects-fomichev-claude/6fa9c75e-eb11-4e5d-98c1-05eb590ab14f/scratchpad/night/1843/ (pw-list.txt, tsc.txt, bytes-compare.txt, split-*), logs/1843-*.log.
## Ночной замер — часть 2 (итог) Сборки: «до» — вершина 1842 `399234a` с `perf/` из этой ветки (`git checkout … -- perf/`, без коммита), «после» — `3e9979d`. Масштаб 1 (D0) и 2 (D2). Прогон по `perf/README.md` «Свод 2 после AURORA-1843» и списку «Проверки для главного контроллера». ### Проверки инструмента | проверка | результат | |---|---| | `PERF_SQLSTATS=0 npx playwright test --list` | **Total: 396 tests in 10 files**, ошибок загрузки нет | | `tsc` (perf/e2e) | **rc=1**: `lib/manifest.ts(32,51): TS2783 'owner' is specified more than once, so this usage will be overwritten`. Строка 32 (`{ owner: 'rf', ...s }`) идентична в `origin/test`, 1842 (399234a) и этой ветке (3e9979d); файл не менялся ни в 1842, ни в 1843: ошибка пришла из PR «каркас замеров фронта» (#203), не из 1843. На вершине 1842 `tsc` отдельно не запускался — вывод по тексту исходников | | `svod2_paging_check.py`, масштаб 1 / масштаб 2 | CHECK_OK (GO 5 617 / RF 8 597 строк; масштаб 2: 22 419 / 34 644; расхождений 0) | | `svod2_search_oracle.mjs --check`, масштаб 1 / 2 | CHECK_OK / CHECK_OK | ### Что в прогоне вышло с rc≠0 и почему - «before split rc=1» (03:20): `api_split.py` из этой ветки запрашивает `/svod/2/GO/2026/facets`, на сервере 1842 его нет — `HTTP 404`. Переснято инструментом 1842 (`perf/` без правок PR 3): `rc=0` (04:11), «до» в #241 взято оттуда. Аналогично «before explain rc=1» (нет функции `v_svod2_go` с новой сигнатурой) → переснято 04:11. - Фильтр GO (`--grep filter`): «filter did not stabilize in 120s» и на «до», и на «после» (`logs/1843-{before,after}-filter.log`), метрик нет; RF-фильтр отработал: 432 → 857 мс. - Первый прогон phase2 (`before`/`after`): клики по select-фильтрам — тайм-аут 30 с (локатор) → в `before2`/`after2` исправлено и повторено. ### Цели design (масштаб 1) | метрика | цель | факт | | |---|---|---|---| | память `final` | ≤ 0.30× | 0.073× (586.8 → 42.6 МБ) | выполнено | | first_rows_ms | ≤ 0.5× | 0.36× / 0.28× (GO / RF) | выполнено | | compact / full | ≤ 0.40 | 0.15 / 0.14 | выполнено | | первая страница + facets | ≤ 5 % | 1.6 % / 1.0 % | выполнено | | прежний запрос | ≤ 1.10× | 1.06× / 1.05× | выполнено | | шаг прокрутки | ≤ 1.10× | 0.90× / 0.86× | выполнено | | placeholder_frame_share | ≤ 5 % | 0 | выполнено формально (см. O-7 в #243) | | память s2 | ≤ 1.25× «после» s1 | не снято | | Не снято: память и прокрутка на масштабе 2 (на s2 снимались только `gen`/`verify`, `api_split`, `paging_check`, oracle, время поиска; фаза 5 закончилась в 05:37). Время серверного поиска (I-1) и O-7 — см. #241 и #243. Файлы: `/private/tmp/claude-501/-Users-andrey-epifancev-projects-fomichev-claude/6fa9c75e-eb11-4e5d-98c1-05eb590ab14f/scratchpad/night/1843/` (pw-list.txt, tsc.txt, bytes-compare.txt, split-*), `logs/1843-*.log`.
aep added 1 commit 2026-10-29 11:37:25 +03:00
aep added 1 commit 2026-10-29 12:18:37 +03:00
aep added 1 commit 2026-10-29 12:22:08 +03:00
This pull request can be merged automatically.
You are not authorized to merge this pull request.

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin feat/236-aurora-1843-svod2-server-paging-perf:feat/236-aurora-1843-svod2-server-paging-perf
git checkout feat/236-aurora-1843-svod2-server-paging-perf
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: RSHB/DFiP_Budget_planing#245
No description provided.