AURORA-1843: свод 2 — догрузка строк страницами, поиск и фильтры через сервер (2/3, фронт) #243

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

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

Что сделано (фаза 2 — фронт)

  • Свод 2 получает строки страницами с сервера (view=compact, страница 300 строк), поиск и три колоночных фильтра считает сервер, варианты фильтров приходят из /facets. В памяти вкладки — окно из трёх страниц (LRU 5) + заглушки; та же таблица MRT, отступы виртуализатора (paddingStart/paddingEnd) задают высоту прокрутки по total.
  • Чистая логика: svod2Paging.js (окно, срез, LRU, параметры, редьюсер состояния вкладки с поколениями, shouldRefine, shouldShowFound); хук useSvod2Pages.js ходит в API (один AbortController на поколение, settled для каждого поколения, нет утечек rAF/контроллеров). SummaryApi.getSvod2Page/getSvod2Facets.
  • Единый источник высоты строки окна — измерение первой строки с данными (по умолчанию 37 px), ROW_VIRTUALIZER_OPTIONS, SvodContext, SvodFilters и свод 1 не менялись.
  • Для пользователя поведение прежнее: подписи, условия disabled, подсказка «Нажмите «Загрузить»…», Alert с «Повторить», сброс колоночных фильтров, «Найдено N из M».

Тесты

  • node --test (RealtimeTable utils, SvodPage, Svod2Page): 52/52; npm run build ок; git grep getSummary|invalidateSummary|matchesSearch в Svod2Page пуст.
  • Проверка предпосылки (Task 9): MRT 3.2.1 разворачивает пользовательские rowVirtualizerOptions последними, высота tbody = getTotalSize().
  • biome: одна ошибка формата в Svod2Page.jsx (scaleNumericColumns, <Tab>) — строки не менялись относительно 399234a.

Чек-лист ручной проверки (главный контроллер, на стенде против сборки «до» на тех же данных)

  • GO и RF, admin и dfip, «Все» и выбор организаций.
  • Поиск, три фильтра и их сочетания, варианты с числами, «Найдено», сброс фильтров.
  • Вкладки и положение прокрутки; ползунок в середину и в конец.
  • Быстрый ввод, затем фильтр; ввод поиска во время первой загрузки; возврат к ранее загруженным условиям (A→B→A).
  • Высота строки (R-9): нет наложения строк и пустоты, «Обновить» на глубине сохраняет позицию; зазоры между заглушками.
  • Варианты select-ов обновляются после смены поиска/фильтров.
  • Единицы, «Перейти к задачам», горизонтальная прокрутка, ошибка догрузки.
  • Скриншот��.

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

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

Refs #236 (часть 2/3; `Closes #236` будет в PR 3). Jira AURORA-1843 (эпик AURORA-1834). Стек: PR 1 (#241) → этот PR → PR 3. Spec: `openspec/changes/aurora-1843-svod2-server-paging/`. ## Что сделано (фаза 2 — фронт) - Свод 2 получает строки страницами с сервера (`view=compact`, страница 300 строк), поиск и три колоночных фильтра считает сервер, варианты фильтров приходят из `/facets`. В памяти вкладки — окно из трёх страниц (LRU 5) + заглушки; та же таблица MRT, отступы виртуализатора (`paddingStart/paddingEnd`) задают высоту прокрутки по `total`. - Чистая логика: `svod2Paging.js` (окно, срез, LRU, параметры, редьюсер состояния вкладки с поколениями, `shouldRefine`, `shouldShowFound`); хук `useSvod2Pages.js` ходит в API (один AbortController на поколение, `settled` для каждого поколения, нет утечек rAF/контроллеров). `SummaryApi.getSvod2Page/getSvod2Facets`. - Единый источник высоты строки окна — измерение первой строки с данными (по умолчанию 37 px), `ROW_VIRTUALIZER_OPTIONS`, `SvodContext`, `SvodFilters` и свод 1 не менялись. - Для пользователя поведение прежнее: подписи, условия `disabled`, подсказка «Нажмите «Загрузить»…», `Alert` с «Повторить», сброс колоночных фильтров, «Найдено N из M». ## Тесты - `node --test` (RealtimeTable utils, SvodPage, Svod2Page): 52/52; `npm run build` ок; `git grep getSummary|invalidateSummary|matchesSearch` в Svod2Page пуст. - Проверка предпосылки (Task 9): MRT 3.2.1 разворачивает пользовательские `rowVirtualizerOptions` последними, высота `tbody` = `getTotalSize()`. - biome: одна ошибка формата в `Svod2Page.jsx` (`scaleNumericColumns`, `<Tab>`) — строки не менялись относительно 399234a. ## Чек-лист ручной проверки (главный контроллер, на стенде против сборки «до» на тех же данных) - [ ] GO и RF, admin и dfip, «Все» и выбор организаций. - [ ] Поиск, три фильтра и их сочетания, варианты с числами, «Найдено», сброс фильтров. - [ ] Вкладки и положение прокрутки; ползунок в середину и в конец. - [ ] Быстрый ввод, затем фильтр; ввод поиска во время первой загрузки; возврат к ранее загруженным условиям (A→B→A). - [ ] Высота строки (R-9): нет наложения строк и пустоты, «Обновить» на глубине сохраняет позицию; зазоры между заглушками. - [ ] Варианты select-ов обновляются после смены поиска/фильтров. - [ ] Единицы, «Перейти к задачам», горизонтальная прокрутка, ошибка догрузки. - [ ] Скриншот��. Замер до/после — добавит контроллер после прогона на стенде. ## 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:18:50 +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>
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>
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-web:feat/236-aurora-1843-svod2-server-paging-web
git checkout feat/236-aurora-1843-svod2-server-paging-web
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#243
No description provided.