AURORA-1843: свод 2 — серверные страницы, поиск, фильтры и варианты (1/3, сервер) #241

Open
aep wants to merge 18 commits from feat/236-aurora-1843-svod2-server-paging into feat/220-aurora-1842-svod2-column-virtual
Owner

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

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

  • Миграция 0053: локаленезависимые svod2_casefold, svod2_js_trim, svod2_js_number_text, проекция svod2_compact; общий отбор svod2_lines; новые v_svod2_go/v_svod2_rf (поиск, три колоночных фильтра, total_count, компактное data); v_svod2_facets.
  • API: GET /svod/2/{sheet}/{year} получает view=full|compact, search, smeta_type, smeta_direction, org_name; ответ нового режима содержит total. Без новых параметров ответ байт-в-байт прежний. Новый GET /svod/2/{sheet}/{year}/facets.
  • Репозиторий, сервис, схемы ответа. get_svod2_rows и v_svod2_go_export не менялись.
  • Значения поиска и фильтров не пишутся в лог db_time (только признаки и длина).

Тесты

  • JS-оракул экрана «до» (perf/analysis/svod2_search_oracle.mjs: matchesSearch и equals дословные копии) порождает векторы; Python-порт сверен с ними; оракул служит эталоном интеграционных тестов API на засеянных данных (поиск, фильтры, варианты, «Найдено», компактная проекция, права isp).
  • Эталон прежнего ответа svod2_legacy_golden.json (sha256, GO/RF × 5 случаев) записан на коде «до» и не менялся.
  • Полный pytest на PG16: 3 известных падения (test_backend_calls_form3_add_project_and_add_line_functions, два теста test_export_service_query_params), 499 passed, 4 skipped.
  • PG15.12 (контур, с коммитами AURORA-1922): те же 3 падения, 501 passed, 4 skipped.

Чек-лист ручной проверки (главный контроллер)

  • Старый фронт работает без изменений (запросы без новых параметров).
  • Прежний ответ байт-в-байт на данных стенда (GO/RF; admin и dfip; все и одна организация; offset=0&limit=50), sha256 распакованных тел до и после миграции.
  • Excel RF: значения ячеек (openpyxl).

Замер до/после — добавит контроллер после прогона на стенде.
PG15 — проверено контроллером SDD (см. выше).

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 (часть 1/3; `Closes #236` будет в PR 3). Jira AURORA-1843 (эпик AURORA-1834). Spec: `openspec/changes/aurora-1843-svod2-server-paging/`. ## Что сделано (фаза 1 — сервер) - Миграция `0053`: локаленезависимые `svod2_casefold`, `svod2_js_trim`, `svod2_js_number_text`, проекция `svod2_compact`; общий отбор `svod2_lines`; новые `v_svod2_go`/`v_svod2_rf` (поиск, три колоночных фильтра, `total_count`, компактное `data`); `v_svod2_facets`. - API: `GET /svod/2/{sheet}/{year}` получает `view=full|compact`, `search`, `smeta_type`, `smeta_direction`, `org_name`; ответ нового режима содержит `total`. Без новых параметров ответ байт-в-байт прежний. Новый `GET /svod/2/{sheet}/{year}/facets`. - Репозиторий, сервис, схемы ответа. `get_svod2_rows` и `v_svod2_go_export` не менялись. - Значения поиска и фильтров не пишутся в лог `db_time` (только признаки и длина). ## Тесты - JS-оракул экрана «до» (`perf/analysis/svod2_search_oracle.mjs`: `matchesSearch` и `equals` дословные копии) порождает векторы; Python-порт сверен с ними; оракул служит эталоном интеграционных тестов API на засеянных данных (поиск, фильтры, варианты, «Найдено», компактная проекция, права isp). - Эталон прежнего ответа `svod2_legacy_golden.json` (sha256, GO/RF × 5 случаев) записан на коде «до» и не менялся. - Полный `pytest` на PG16: 3 известных падения (`test_backend_calls_form3_add_project_and_add_line_functions`, два теста `test_export_service_query_params`), 499 passed, 4 skipped. - PG15.12 (контур, с коммитами AURORA-1922): те же 3 падения, 501 passed, 4 skipped. ## Чек-лист ручной проверки (главный контроллер) - [ ] Старый фронт работает без изменений (запросы без новых параметров). - [ ] Прежний ответ байт-в-байт на данных стенда (GO/RF; admin и dfip; все и одна организация; `offset=0&limit=50`), sha256 распакованных тел до и после миграции. - [ ] Excel RF: значения ячеек (openpyxl). Замер до/после — добавит контроллер после прогона на стенде. PG15 — проверено контроллером SDD (см. выше). ## 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 16 commits 2026-10-28 21:16:04 +03:00
Свод 2: серверная постраничная загрузка (поиск, три фильтра, total,
варианты фильтров) и компактный ответ; фронт догружает строки окном
страниц; замеры памяти, времени до первых строк, байтов и шага скролла.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Поиск, колоночные фильтры, варианты фильтров и «Найдено N из M» — с точной
семантикой экрана (matchesSearch, MRT equals, faceting TanStack); регистр
без зависимости от локали БД; пороги — цели, а не условие слияния;
решения контроллера (три фазы/ветки, prefetch страницы 1, окружение тестов).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Три фазы — три PR стеком: сервер (SQL, API, тесты-оракулы первыми),
фронт (окно страниц в той же таблице), стенд замеров. Решения плана
дописаны в design.md (#23–#34).

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 Sonnet 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>
- M-1: поиск по перекрытым полям contract_summary (ооо лютик, дс-2, дс-1) и неперекрытому (70), явные assert для строки 910004
- M-2: в лог db_time вместо значений поиска и фильтров пишутся признаки has_*/search_len; unit-тест на caplog
- M-5: total читается по имени столбца total_count

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

Ночная проверка корректности на стенде perf/ (29.10, масштаб 1, D0 без grow) — блокеры из «Передано контроллеру»

Сборки: «до» — вершина 1842 399234a (БД на 0049) с perf/ из PR 3 (git checkout ...-perf -- perf/, без коммита); «после» — вершина PR 3 3e9979d (включает #241 782a043 и #243 fbc3601), alembic upgrade → 0053. Одни данные (дамп D0).

(1) Байт-в-байт прежнего режима до/после 0053 — выполнено

GET /api/v1/svod/2/{GO,RF}/2026 под admin и dfip, по 6 вариантов: без параметров; org_ids=<одна организация>; offset=0&limit=50; org_ids+offset/limit; sort_by=section_code&sort_direction=desc; offset=50&limit=50. sha256 распакованных тел: 24 из 24 совпали (GO все 30 911 911 байт, RF все 47 225 805 байт).
Excel (/export/summary/2/{RF,GO}/2026, admin), значения ячеек через openpyxl: лист данных RF 8600 строк и GO 5620 строк — идентичны; единственная разница — ячейка B5 листа metadata (время выгрузки), ожидаемо.

(2) Сверки — выполнено

  • analysis/svod2_paging_check.py --scale 1: GO full/compact 5617 строк, RF full/compact 8597 строк — расхождений 0, CHECK_OK.
  • node analysis/svod2_search_oracle.mjs --check --api http://localhost:8000 --username perf_dfip ... --year 2026: CHECK_OK.

Замеры фазы 2/3 (скриншоты, O-7, время серверного поиска I-1, масштаб 1) — отдельным комментарием в #243/#245 по готовности.

Файлы: /private/tmp/claude-501/-Users-andrey-epifancev-projects-fomichev-claude/6fa9c75e-eb11-4e5d-98c1-05eb590ab14f/scratchpad/night/1843/ (bytes-before, bytes-after с index.json и xlsx, bytes-compare.txt, paging_check.txt, oracle_check.txt; скрипт night/tools/svod2_bytes.py).

🤖 Generated with Claude Code

## Ночная проверка корректности на стенде perf/ (29.10, масштаб 1, D0 без grow) — блокеры из «Передано контроллеру» **Сборки:** «до» — вершина 1842 `399234a` (БД на 0049) с `perf/` из PR 3 (`git checkout ...-perf -- perf/`, без коммита); «после» — вершина PR 3 `3e9979d` (включает #241 782a043 и #243 fbc3601), `alembic upgrade` → 0053. Одни данные (дамп D0). ### (1) Байт-в-байт прежнего режима до/после 0053 — **выполнено** GET `/api/v1/svod/2/{GO,RF}/2026` под admin и dfip, по 6 вариантов: без параметров; `org_ids=<одна организация>`; `offset=0&limit=50`; `org_ids+offset/limit`; `sort_by=section_code&sort_direction=desc`; `offset=50&limit=50`. sha256 распакованных тел: **24 из 24 совпали** (GO все 30 911 911 байт, RF все 47 225 805 байт). Excel (`/export/summary/2/{RF,GO}/2026`, admin), значения ячеек через openpyxl: лист данных RF 8600 строк и GO 5620 строк — **идентичны**; единственная разница — ячейка B5 листа `metadata` (время выгрузки), ожидаемо. ### (2) Сверки — **выполнено** - `analysis/svod2_paging_check.py --scale 1`: GO full/compact 5617 строк, RF full/compact 8597 строк — расхождений 0, **CHECK_OK**. - `node analysis/svod2_search_oracle.mjs --check --api http://localhost:8000 --username perf_dfip ... --year 2026`: **CHECK_OK**. Замеры фазы 2/3 (скриншоты, O-7, время серверного поиска I-1, масштаб 1) — отдельным комментарием в #243/#245 по готовности. Файлы: `/private/tmp/claude-501/-Users-andrey-epifancev-projects-fomichev-claude/6fa9c75e-eb11-4e5d-98c1-05eb590ab14f/scratchpad/night/1843/` (bytes-before, bytes-after с index.json и xlsx, bytes-compare.txt, paging_check.txt, oracle_check.txt; скрипт `night/tools/svod2_bytes.py`). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Author
Owner

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

Сборки как в части 1: «до» — вершина 1842 399234a (БД 0049, perf/ из PR 3), «после» — вершина PR 3 3e9979d (0053); данные D0 (масштаб 1) и D2 (масштаб 2). Корректность части 1 (байт-в-байт 24/24, Excel, CHECK_OK × 2) — в моём предыдущем комментарии; новое ниже.

Корректность

  • Масштаб 2 (22 419 GO / 34 644 RF): svod2_paging_check.py — full/compact GO и RF, расхождений 0, CHECK_OK; svod2_search_oracle.mjs --check — CHECK_OK.
  • Блокеры из «Передано контроллеру» выполнены: прежний режим побайтно, паджинг/поиск/варианты сверены с оракулом на масштабах 1 и 2.

Скорость API (api_split.py, масштаб 1, мс полное / БД; «до» — инструмент 1842, «после» — инструмент PR 3; две отдельные сессии)

запрос до после
свод 2 GO, прежний режим (30,9 МБ) 973.1 / 637.4 1030.0 (1.06×) / 680.9
свод 2 RF, прежний режим (47,2 МБ) 1466.3 / 934.5 1543.7 (1.05×) / 1019.8
GO страница 300, full / compact — 150.5 / 150.9 (1,66 МБ / 250 КБ, compact/full = 0.15)
RF страница 300, full / compact — 207.6 / 193.5 (1,64 МБ / 232 КБ, 0.14)
facets GO / RF — 47.0 / 66.3
RF compact + поиск '1' — 427.3
Для сравнения: не затронутые PR FORM_4/CAP и FORM_4/AHR в тех же двух прогонах отличаются на +6 % и +8 % — разброс между сессиями того же порядка. Цель «прежний запрос ≤ 1.10×» — выполнена.
Масштаб 2 (s2/split-1843-after, после gen/ANALYZE): страница GO compact 517 (БД 501), RF 760 (746); facets GO 225, RF 350; прежний режим GO 4425 (Python 1497), RF 6853 (2304). «До» на масштабе 2 для 1843 не снималось.

Время серверного поиска (I-1)

Запросы по 5 раз, медиана; полное / БД, мс (1843/search-timing.txt, s2/search-timing.txt):

запрос масштаб 1 масштаб 2
GO page0 compact (без поиска) 151 / 131 513 / 500
GO поиск '1' 282 / 264 1057 / 1044
GO поиск 'аренд' (7 / 43 строки) 729 / 722 2996 / 2976
GO поиск 'РФ-01' 630 / 615 2527 / 2512
GO поиск 'zzzz' (пусто) 568 / 561 2354 / 2348
RF page0 compact 191 / 176 755 / 737
RF поиск 'аренд' (0 строк) 1131 / 1126 4687 / 4681
RF поиск 'РФ-01' 942 / 924 3886 / 3868
RF поиск 'zzzz' (пусто) 888 / 880 3716 / 3710
facets при поиске 'аренд' GO / RF 737 / 1131 3012 / 4775
filter smeta_type=АХР GO / RF 112 / 127 267 / 342
Рост ×4 по строкам даёт ×4,1 по времени поиска, то есть линейный; почти всё время — в БД. Сравнение с «до»: время самого клиентского поиска отдельно не измерялось; на экране (search_aренд.ms_to_stable, от в��ода «аренд» до стабильного «Найдено N из M», включая debounce, одна процедура на обеих сборках): до 349 / 342 / 352 мс (dfip GO, dfip RF, admin GO), после 788–1315 / 877–1559 / 1151–1159 мс (два прогона) — ×2,3–4,6. Экранное время на масштабе 2 не снималось. Порога на время поиска в design нет.

O-7: пустые строки после прыжка (подробнее в #243)

Через ~50 мс после прыжка ползунком в середину или в конец «до» показывает данные, «после» — 17 пустых строк (без текста и без полос-скелетонов, высота 37.00 против 37.44 у settled), текст появляется к следующему опросу (≈ 55 мс на масштабе 1, локально); при «Обновить» на глубине скелетоны (серые полосы) есть и «до», и «после». Решение — за человеком.

Вердикт: корректность — выполнена (блокеры сняты); цели design по серверу (compact/full ≤ 0.40: 0.15 / 0.14; первая страница + facets ≤ 5 %: 1.6 % / 1.0 %; прежний запрос ≤ 1.10×: 1.06 / 1.05) — выполнены. I-1: серверный поиск заметно медленнее экранного «до» — решение за человеком (R-5: правка предиката допустима в 0053 до слияния).
Файлы: /private/tmp/claude-501/-Users-andrey-epifancev-projects-fomichev-claude/6fa9c75e-eb11-4e5d-98c1-05eb590ab14f/scratchpad/night/1843/ (split-, search-timing.txt, explain-), s2/ (paging_check.txt, oracle_check.txt, search-timing.txt, split-1843-after).

## Ночной замер — часть 2 (итог) Сборки как в части 1: «до» — вершина 1842 `399234a` (БД 0049, `perf/` из PR 3), «после» — вершина PR 3 `3e9979d` (0053); данные D0 (масштаб 1) и D2 (масштаб 2). Корректность части 1 (байт-в-байт 24/24, Excel, CHECK_OK × 2) — в моём предыдущем комментарии; новое ниже. ### Корректность - Масштаб 2 (22 419 GO / 34 644 RF): `svod2_paging_check.py` — full/compact GO и RF, расхождений 0, **CHECK_OK**; `svod2_search_oracle.mjs --check` — **CHECK_OK**. - Блокеры из «Передано контроллеру» выполнены: прежний режим побайтно, паджинг/поиск/варианты сверены с оракулом на масштабах 1 и 2. ### Скорость API (`api_split.py`, масштаб 1, мс полное / БД; «до» — инструмент 1842, «после» — инструмент PR 3; две отдельные сессии) | запрос | до | после | |---|---|---| | свод 2 GO, прежний режим (30,9 МБ) | 973.1 / 637.4 | 1030.0 (1.06×) / 680.9 | | свод 2 RF, прежний режим (47,2 МБ) | 1466.3 / 934.5 | 1543.7 (1.05×) / 1019.8 | | GO страница 300, full / compact | — | 150.5 / 150.9 (1,66 МБ / 250 КБ, compact/full = 0.15) | | RF страница 300, full / compact | — | 207.6 / 193.5 (1,64 МБ / 232 КБ, 0.14) | | facets GO / RF | — | 47.0 / 66.3 | | RF compact + поиск '1' | — | 427.3 | Для сравнения: не затронутые PR FORM_4/CAP и FORM_4/AHR в тех же двух прогонах отличаются на +6 % и +8 % — разброс между сессиями того же порядка. **Цель «прежний запрос ≤ 1.10×» — выполнена.** Масштаб 2 (`s2/split-1843-after`, после `gen`/`ANALYZE`): страница GO compact 517 (БД 501), RF 760 (746); facets GO 225, RF 350; прежний режим GO 4425 (Python 1497), RF 6853 (2304). «До» на масштабе 2 для 1843 не снималось. ### Время серверного поиска (I-1) Запросы по 5 раз, медиана; полное / БД, мс (`1843/search-timing.txt`, `s2/search-timing.txt`): | запрос | масштаб 1 | масштаб 2 | |---|---|---| | GO page0 compact (без поиска) | 151 / 131 | 513 / 500 | | GO поиск '1' | 282 / 264 | 1057 / 1044 | | GO поиск 'аренд' (7 / 43 строки) | 729 / 722 | 2996 / 2976 | | GO поиск 'РФ-01' | 630 / 615 | 2527 / 2512 | | GO поиск 'zzzz' (пусто) | 568 / 561 | 2354 / 2348 | | RF page0 compact | 191 / 176 | 755 / 737 | | **RF поиск 'аренд' (0 строк)** | **1131 / 1126** | **4687 / 4681** | | RF поиск 'РФ-01' | 942 / 924 | 3886 / 3868 | | **RF поиск 'zzzz' (пусто)** | **888 / 880** | **3716 / 3710** | | facets при поиске 'аренд' GO / RF | 737 / 1131 | 3012 / 4775 | | filter smeta_type=АХР GO / RF | 112 / 127 | 267 / 342 | Рост ×4 по строкам даёт ×4,1 по времени поиска, то есть линейный; почти всё время — в БД. **Сравнение с «до»:** время самого клиентского поиска отдельно не измерялось; на экране (`search_aренд.ms_to_stable`, от в��ода «аренд» до стабильного «Найдено N из M», включая debounce, одна процедура на обеих сборках): до 349 / 342 / 352 мс (dfip GO, dfip RF, admin GO), после 788–1315 / 877–1559 / 1151–1159 мс (два прогона) — **×2,3–4,6**. Экранное время на масштабе 2 не снималось. Порога на время поиска в design нет. ### O-7: пустые строки после прыжка (подробнее в #243) Через ~50 мс после прыжка ползунком в середину или в конец «до» показывает данные, «после» — 17 пустых строк (без текста и без полос-скелетонов, высота 37.00 против 37.44 у settled), текст появляется к следующему опросу (≈ 55 мс на масштабе 1, локально); при «Обновить» на глубине скелетоны (серые полосы) есть и «до», и «после». Решение — за человеком. **Вердикт:** корректность — выполнена (блокеры сняты); цели design по серверу (compact/full ≤ 0.40: 0.15 / 0.14; первая страница + facets ≤ 5 %: 1.6 % / 1.0 %; прежний запрос ≤ 1.10×: 1.06 / 1.05) — **выполнены**. I-1: серверный поиск заметно медленнее экранного «до» — решение за человеком (R-5: правка предиката допустима в 0053 до слияния). Файлы: `/private/tmp/claude-501/-Users-andrey-epifancev-projects-fomichev-claude/6fa9c75e-eb11-4e5d-98c1-05eb590ab14f/scratchpad/night/1843/` (split-*, search-timing.txt, explain-*), `s2/` (paging_check.txt, oracle_check.txt, search-timing.txt, split-1843-after).
aep added 1 commit 2026-10-29 11:36:22 +03:00
aep added 1 commit 2026-10-29 13:07:13 +03:00
Поиск в v3.svod2_lines строил jsonb header || contract_summary || contract_detail на каждую
строку, разворачивал его в jsonb_each и прогонял каждое значение через svod2_casefold, а числа
через svod2_js_number_text. Теперь:
- разбор поисковой строки (числа возможны, нет U+0001, нужные пары таблицы регистра) делается
  один раз в CTE q; раньше при подстановке SQL-функции выражение нормализации p_search
  вычислялось на каждое значение каждой строки;
- значения берутся напрямую из колонок, без jsonb; склеиваются и проверяются одним strpos через
  разделитель U+0001 (со строкой поиска, где есть U+0001, значения проверяются по одному);
- регистр данных приводится только по парам таблицы, чей результат есть в строке поиска;
- числа в текст JS переводятся, только если все символы строки возможны в записи числа, и
  только если по остальным значениям совпадения нет; нули без обращения к plpgsql;
- v_svod2_go и v_svod2_rf с SET jit = off (JIT плана добавлял сотни миллисекунд).

Тесты: поиск svod2_lines равен прежнему поиску по jsonb (эталонный SQL в тесте) на обоих листах
для 55 строк, включая числа, экспоненту, NaN и Infinity, стык значений, U+0001, ненормализованные
строки; состав колонок contract_* закреплён тестом.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
tsygankoviva approved these changes 2026-10-30 18:01:01 +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:feat/236-aurora-1843-svod2-server-paging
git checkout feat/236-aurora-1843-svod2-server-paging
Sign in to join this conversation.
No Reviewers
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: RSHB/DFiP_Budget_planing#241
No description provided.