openspec: архив aurora-1843-svod2-server-paging (PR #241/#243/#245)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
40a84acdb0
commit
f9fbd7399f
162
openspec/specs/summary2-api/spec.md
Normal file
162
openspec/specs/summary2-api/spec.md
Normal file
@ -0,0 +1,162 @@
|
||||
# summary2-api Specification
|
||||
|
||||
## Purpose
|
||||
Контракт API свода 2 (`/api/v1/svod/2/...`): постраничная выдача строк листа GO или RF с общим числом строк, серверные поиск и колоночные фильтры с той же семантикой, что у экрана до изменения, варианты колоночных фильтров, компактное представление строки и совместимость прежнего ответа для выгрузки, тестов и стенда замеров.
|
||||
|
||||
## Requirements
|
||||
|
||||
### Requirement: Прежний ответ без новых параметров
|
||||
Запрос `GET /api/v1/svod/2/{sheet}/{year}`, в котором нет ни одного из параметров `view`, `search`, `smeta_type`, `smeta_direction`, `org_name`, SHALL возвращать ответ, байт-в-байт совпадающий с ответом до изменения на тех же данных и с теми же `org_ids`, `offset`, `limit`, `sort_by`, `sort_direction`. Совпадать должны набор и порядок строк, `sort_order`, содержимое `data` со всеми ключами, включая `null`, и верхний уровень `success`/`message`/`result`/`count`. Поля `total` в таком ответе SHALL NOT быть. Excel-выгрузка свода 2 SHALL выдавать то же содержимое, что до изменения. Это условие слияния.
|
||||
|
||||
#### Scenario: Полный ответ «все организации» не изменился
|
||||
- **WHEN** на одних и тех же данных стенда выполняются `GET /api/v1/svod/2/GO/{year}` и `GET /api/v1/svod/2/RF/{year}` без параметров до и после изменения (роли admin и dfip, все организации и одна организация, `offset=0&limit=50`)
|
||||
- **THEN** тела ответов после распаковки совпадают побайтно (одинаковый sha256)
|
||||
|
||||
#### Scenario: Прежняя пагинация без total
|
||||
- **WHEN** выполняется `GET /api/v1/svod/2/GO/{year}?offset=0&limit=2`
|
||||
- **THEN** ответ содержит `count` не больше 2, `result` не длиннее 2 строк и не содержит ключа `total`
|
||||
|
||||
#### Scenario: Невалидные прежние параметры
|
||||
- **WHEN** передан `offset=-1`, `limit=0`, `sort_by=bad` или `sort_direction=bad`
|
||||
- **THEN** ответ — 422, как до изменения
|
||||
|
||||
### Requirement: Постраничная выдача с общим числом строк
|
||||
Если в запросе есть хотя бы один из параметров `view`, `search`, `smeta_type`, `smeta_direction`, `org_name` (это «новый режим»), ответ SHALL содержать поле `total`. `total` — число строк, удовлетворяющих всем условиям запроса (год, `org_ids`, поиск, колоночные фильтры), без учёта `offset` и `limit`. `count` SHALL по-прежнему равняться длине `result`. Строки SHALL идти в том же порядке, что в полном ответе с теми же условиями: `sort_order` — номер строки в этом порядке, начиная с 1. Страницы с последовательными `offset` при `limit = L` SHALL в объединении давать ровно полный список без пропусков и повторов, если данные между запросами не менялись. Если `offset` не меньше `total`, `result` SHALL быть пустым, а `total` — верным. Это условие слияния.
|
||||
|
||||
#### Scenario: Склейка страниц равна полному списку
|
||||
- **WHEN** при неизменных данных запрашиваются страницы `offset = 0, L, 2L, …` с `limit = L` и `view=full`, пока страница не станет короче `L`
|
||||
- **THEN** последовательность `data.line_id` по всем страницам совпадает с последовательностью в ответе без `offset`/`limit` с теми же условиями, а `total` на каждой странице равен длине этого полного списка
|
||||
|
||||
#### Scenario: Страница за концом списка
|
||||
- **WHEN** в новом режиме запрашивается `offset = total`
|
||||
- **THEN** `result` пустой, `count` = 0, `total` равен числу строк по условиям запроса
|
||||
|
||||
#### Scenario: Явный view=full включает total
|
||||
- **WHEN** выполняется `GET /api/v1/svod/2/RF/{year}?view=full&offset=0&limit=50`
|
||||
- **THEN** строки в `data` совпадают с прежним полным представлением тех же строк, а в ответе есть `total`
|
||||
|
||||
### Requirement: Серверный поиск с семантикой экрана
|
||||
Параметр `search` SHALL отбирать ровно те строки, которые до изменения оставлял поиск экрана:
|
||||
1. Запрос нормализуется как `search.trim().toLowerCase()` в JavaScript (обрезка пробельных символов по правилам ECMAScript `String.prototype.trim`). Если после нормализации строка пустая, выборка SHALL NOT сужаться.
|
||||
2. Строка проходит отбор, если нормализованный запрос входит подстрокой хотя бы в одно значение объекта, полученного слиянием `{...data.header, ...data.contract_summary, ...data.contract_detail}` (поздние группы перекрывают одноимённые ключи ранних). Поля `contract_summary`, одноимённые полям `contract_detail` (`counterparty`, `reference`, `deadline`, `comment`), поэтому SHALL NOT участвовать в поиске.
|
||||
3. Каждое значение приводится к тексту как `String(value ?? '').toLowerCase()` в JavaScript:
|
||||
- `null` — пустая строка;
|
||||
- строка — как есть;
|
||||
- число — по правилам `Number.prototype.toString` для двойной точности, которую экран получил из JSON ответа (например, `1234.50` → `1234.5`, `100.00` → `100`, `1e-7` → `1e-7`).
|
||||
4. Значения берутся такими, какими они приходят в ответе этого листа. Например, на листе RF `contract_detail.expenses_q1..4` — это значения ответа (`COALESCE` договора и ЦКК).
|
||||
5. Приведение к нижнему регистру SHALL NOT зависеть от локали базы данных. Для латиницы ASCII и кириллицы (включая Ё и буквы U+0400–U+042F, U+0490) результат SHALL совпадать с `toLowerCase()`.
|
||||
|
||||
Поиск сочетается с остальными условиями по «И». Длина `search` API не ограничивает: любой запрос даёт тот же результат, что поиск экрана (совпадения есть или их нет), без ошибки.
|
||||
|
||||
#### Scenario: Поиск без учёта регистра по кириллице независимо от локали
|
||||
- **WHEN** в данных есть строка с `header.name = «Аренда помещения»`, база работает с `LC_CTYPE=C` или `en_US.utf8`, и выполняется запрос с `search=аРЕНДА`
|
||||
- **THEN** в обоих случаях строка есть в выдаче, а `total` равен числу строк, отобранных поиском экрана до изменения
|
||||
|
||||
#### Scenario: Перекрытые поля contract_summary не ищутся
|
||||
- **WHEN** у строки `contract_summary.counterparty = «ООО Ромашка»`, а `contract_detail.counterparty` пустой, и ни одно другое поле не содержит «ромаш»
|
||||
- **THEN** при `search=ромаш` строки нет в выдаче, как и на экране до изменения
|
||||
|
||||
#### Scenario: Поиск по договору
|
||||
- **WHEN** у строки `contract_detail.counterparty = «ООО Ромашка»` и `search=ромаш`
|
||||
- **THEN** строка есть в выдаче
|
||||
|
||||
#### Scenario: Числа ищутся в записи JavaScript
|
||||
- **WHEN** у строки `contract_detail.ceiling_amount = 1234.50` в БД
|
||||
- **THEN** `search=1234.5` находит строку, а `search=1234.50` не находит
|
||||
|
||||
#### Scenario: Очень длинный поиск без ошибки
|
||||
- **WHEN** передан `search` длиной 5000 символов, которого нет ни в одном значении
|
||||
- **THEN** ответ — 200 с пустым `result` и `total` = 0, как пустой результат поиска на экране
|
||||
|
||||
#### Scenario: Пустой поиск не сужает
|
||||
- **WHEN** в новом режиме передан `search` из одних пробельных символов
|
||||
- **THEN** `total` равен `total` того же запроса без `search`
|
||||
|
||||
#### Scenario: Сверка с поиском экрана на данных стенда
|
||||
- **WHEN** для GO и RF масштаба 1 по набору запросов (`аренда`, `АРЕНДА`, `1`, `,`, подстрока названия организации, подстрока контрагента, дробное число из данных) серверная выдача сравнивается с функцией `matchesSearch` экрана до изменения, применённой в Node.js к прежнему полному ответу
|
||||
- **THEN** множества и порядок `line_id` совпадают для каждого запроса
|
||||
|
||||
### Requirement: Колоночные фильтры с семантикой экрана
|
||||
Параметры `smeta_type`, `smeta_direction` и `org_name` SHALL оставлять строки, у которых соответствующее значение (`data.header.smeta_type`, `data.header.smeta_direction`, `data.header.org_name`) не `null` и после `toLowerCase().trim()` равно значению параметра после `toLowerCase().trim()`. Это семантика фильтра `equals` таблицы экрана до изменения. Пустое значение параметра SHALL NOT сужать выборку. Длина значений API не ограничивает, ошибки из-за длины нет. Все условия, включая `org_ids` и `search`, сочетаются по «И». `org_ids`, как и раньше, пересекается с организациями, разрешёнными пользователю.
|
||||
|
||||
#### Scenario: Фильтр по виду сметы
|
||||
- **WHEN** запрос с `smeta_type=КВ`
|
||||
- **THEN** у всех строк выдачи `data.header.smeta_type = «КВ»`, а `total` равен числу таких строк в полном ответе с теми же организациями
|
||||
|
||||
#### Scenario: Организации с одинаковым названием
|
||||
- **WHEN** у двух организаций одинаковое название и запрос передаёт `org_name` с этим названием
|
||||
- **THEN** в выдаче строки обеих организаций, как при выборе этого значения в фильтре «ССП» на экране до изменения
|
||||
|
||||
#### Scenario: Комбинация условий
|
||||
- **WHEN** запрос с `search=X`, `smeta_direction=Развитие` и `org_name=<название>`
|
||||
- **THEN** выдача — пересечение трёх условий, её состав совпадает с тем, что экран до изменения показывал при тех же поиске и фильтрах
|
||||
|
||||
### Requirement: Варианты колоночных фильтров с семантикой экрана
|
||||
`GET /api/v1/svod/2/{sheet}/{year}/facets` принимает `org_ids`, `search`, `smeta_type`, `smeta_direction`, `org_name` с тем же смыслом, что у страниц. Ответ SHALL содержать:
|
||||
- `total` — число строк по году и `org_ids` без поиска и фильтров (M в «Найдено N из M»);
|
||||
- `search_total` — число строк по году, `org_ids` и поиску без колоночных фильтров (N в «Найдено N из M»);
|
||||
- для каждой из колонок `smeta_type`, `smeta_direction`, `org_name` — пары «значение → число строк». Они считаются по строкам, отобранным годом, `org_ids`, поиском и фильтрами **двух других** колонок; фильтр самой колонки не применяется. Значения различаются точным совпадением строк, `null` не выдаётся.
|
||||
|
||||
Это семантика вариантов (`getFacetedUniqueValues`) таблицы экрана до изменения, где поиск применялся к данным до таблицы. Неизвестный `sheet` SHALL давать 404. Это условие слияния.
|
||||
|
||||
#### Scenario: Варианты с учётом поиска и других фильтров
|
||||
- **WHEN** задан поиск `X` и фильтр `smeta_type=КВ`
|
||||
- **THEN** варианты `smeta_direction` и `org_name` с числами строк посчитаны по строкам, найденным по `X` с видом сметы «КВ», а варианты `smeta_type` — по строкам, найденным по `X`, без фильтра вида сметы
|
||||
|
||||
#### Scenario: Варианты совпадают с вычисленными по полному ответу
|
||||
- **WHEN** для набора сочетаний поиска и фильтров запрошены `/facets` и прежний полный ответ того же листа, года и `org_ids`
|
||||
- **THEN** `total`, `search_total` и пары «значение → число» совпадают с вычисленными по полному ответу по правилам выше
|
||||
|
||||
#### Scenario: Неизвестный лист
|
||||
- **WHEN** запрошен `/api/v1/svod/2/XX/{year}/facets`
|
||||
- **THEN** ответ — 404
|
||||
|
||||
### Requirement: Компактное представление строки
|
||||
При `view=compact` поле `data` каждой строки SHALL содержать только поля ниже, со значениями, равными значениям тех же путей в полном представлении:
|
||||
|
||||
| группа | поля |
|
||||
|---|---|
|
||||
| верхний уровень | `line_id` |
|
||||
| `header` | `source_form`, `source_id`, `smeta_type`, `smeta_direction`, `org_name`, `name`, `item_id`, `num_group`, `justification` |
|
||||
| `plan` | `plan_q1..4` |
|
||||
| `allocation` | `internal_order`, `property_object` |
|
||||
| `sequestration.DFIP` | `adj_q1..4` |
|
||||
| `reserve` | `amount_q1..4` |
|
||||
| `approved` | `approved_q1..4` |
|
||||
| `contract_detail` | `counterparty`, `reference`, `subject`, `currency`, `ceiling_amount`, `expenses_q1..4`, `vat_rate`, `deadline` |
|
||||
| `q1`–`q4` | `adj_current`, `adj_ssp`, `adj_rf`, `adj_reserve`, `payment_date`, `payment_amount`, `payment_amount_ho`, `payment_amount_rf`, `payment_act`, `booking_amount`, `actual_m1..3` |
|
||||
| только `q4` | `actual_spod` |
|
||||
| `q1`–`q3` | `transfer_to_q<k>` для всех k больше номера квартала, `transfer_to_economy` |
|
||||
| `q2`–`q4` | `plan_revision_eco_change`, `plan_revision_item_adj`, `plan_revision_increase`, `plan_revision_sequester` |
|
||||
|
||||
Ключи со значением `null` SHALL отсутствовать. Нулевые числа SHALL сохраняться. Обёртка строки (`row_type`, `depth`, `sort_order`) SHALL совпадать с полным представлением.
|
||||
|
||||
#### Scenario: Компактная строка — проекция полной
|
||||
- **WHEN** одна и та же страница запрошена с `view=full` и с `view=compact`
|
||||
- **THEN** строки идут в одном порядке, и для каждой строки компактное `data` равно проекции полного `data` на перечисленные пути без ключей со значением `null`
|
||||
|
||||
#### Scenario: Ноль не теряется
|
||||
- **WHEN** в полном представлении `plan.plan_q1 = 0`
|
||||
- **THEN** в компактном `plan.plan_q1 = 0`
|
||||
|
||||
### Requirement: Права доступа на страницы и варианты
|
||||
Для не-администратора выдача страниц, `total` и варианты фильтров SHALL строиться только по организациям, привязанным к пользователю. Запрошенные `org_ids` вне этого множества SHALL отбрасываться, как в прежнем режиме. Если пересечение пусто, ответ SHALL быть пустым: `result` пустой, `total` = 0, `search_total` = 0, списки вариантов пусты.
|
||||
|
||||
#### Scenario: Чужая организация в выборке
|
||||
- **WHEN** исполнитель, привязанный к организации A, запрашивает страницу и `/facets` с `org_ids=<B>`
|
||||
- **THEN** `result` пустой, `total` = 0, варианты пусты
|
||||
|
||||
### Requirement: Замер размера и стоимости ответа
|
||||
Для GO и RF на масштабах 1 и 2 SHALL быть сняты и приведены в PR цифры «до/после». Цифры условием слияния не являются: недобор оформляется follow-up задачей. Что снимается:
|
||||
- распакованный размер страницы `view=compact` и той же страницы `view=full`;
|
||||
- распакованный размер первой страницы и вариантов против прежнего полного ответа;
|
||||
- медиана времени прежнего полного запроса.
|
||||
|
||||
Целевые значения:
|
||||
- `compact` не больше 40 % `full`;
|
||||
- первая страница вместе с вариантами не больше 5 % прежнего полного ответа;
|
||||
- время прежнего запроса не больше 1,10 значения «до».
|
||||
|
||||
#### Scenario: Замер размеров на стенде
|
||||
- **WHEN** `perf/analysis/api_split.py --scale <N>` выполняет для GO и RF полный прежний запрос, страницу `offset=0&limit=<размер страницы>` с `view=full` и с `view=compact` и запрос `/facets`
|
||||
- **THEN** в отчёте PR есть отношения размеров и времён к целевым значениям, а каждый недобор записан как follow-up
|
||||
107
openspec/specs/summary2-screen/spec.md
Normal file
107
openspec/specs/summary2-screen/spec.md
Normal file
@ -0,0 +1,107 @@
|
||||
# summary2-screen Specification
|
||||
|
||||
## Purpose
|
||||
Поведение экрана свода 2 (`/svod/2`, вкладки «ССП» и «РФ») при загрузке строк страницами: для пользователя всё остаётся таким же, как до изменения (поиск, колоночные фильтры, варианты фильтров, «Найдено N из M», вкладки, прокрутка), а в памяти держится ограниченное окно строк. Плюс замеры производительности экрана: память, время до первых строк, шаг прокрутки.
|
||||
|
||||
## Requirements
|
||||
|
||||
### Requirement: Поведение для пользователя не меняется
|
||||
Всё, что пользователь видит и делает на экране свода 2, SHALL остаться таким же, как до изменения, при тех же данных:
|
||||
- набор и порядок строк при любых сочетаниях года, ССП/РФ, поиска и колоночных фильтров;
|
||||
- варианты колоночных фильтров и числа в скобках у вариантов;
|
||||
- подпись «Найдено N из M строк» и момент её показа;
|
||||
- сброс колоночных фильтров;
|
||||
- поведение вкладок, «Загрузить», «Обновить», «Перейти к задачам», единиц;
|
||||
- колонки, форматирование и оформление.
|
||||
|
||||
Допустимые отличия:
|
||||
- время ожидания ответа сервера после ввода поиска или выбора фильтра;
|
||||
- пустые строки-заглушки на месте ещё не пришедших строк при быстрой прокрутке.
|
||||
|
||||
#### Scenario: Визуальный паритет
|
||||
- **WHEN** на одних данных открыть GO «все» до и после изменения и сравнить первые экраны и три позиции горизонтальной прокрутки
|
||||
- **THEN** значения ячеек, прочерки и оформление совпадают
|
||||
|
||||
#### Scenario: Сброс колоночных фильтров
|
||||
- **WHEN** задан колоночный фильтр, и пользователь меняет строку поиска, год или выбор ССП/РФ
|
||||
- **THEN** колоночные фильтры вкладки сбрасываются, как до изменения
|
||||
|
||||
### Requirement: Загрузка строк страницами при прокрутке
|
||||
После нажатия «Загрузить» или «Обновить» экран SHALL запрашивать с сервера страницы, покрывающие видимую область и по одной соседней странице с каждой стороны. При положении прокрутки в начале это страницы с `offset=0` и `offset=<размер страницы>`; вторая запрашивается сразу, чтобы при подходе к её строкам не было заглушек. Вместе со страницами запрашиваются варианты фильтров. Полная длина полосы прокрутки SHALL соответствовать общему числу строк по текущим условиям. Строки, которые ещё не пришли, SHALL показываться пустыми строками-заглушками той же высоты: без значений и без прочерков. Когда видимая область доходит до незагруженных строк, экран SHALL их запросить и заменить заглушки данными без сдвига прокрутки. Экран SHALL NOT менять положение прокрутки программно: оно ведёт себя так же, как раньше при смене данных в той же таблице. В памяти SHALL держаться строки не более чем фиксированного числа страниц, независимо от общего числа строк.
|
||||
|
||||
#### Scenario: Первая загрузка «Все ССП/РФ»
|
||||
- **WHEN** пользователь выбирает «Все ССП/РФ» на вкладке «ССП» и нажимает «Загрузить», а прокрутка в начале
|
||||
- **THEN** экран запрашивает варианты фильтров и страницы `offset=0` и `offset=<размер страницы>`, показывает первые строки, а высота прокрутки соответствует `total` строкам
|
||||
|
||||
#### Scenario: Прокрутка в середину и в конец
|
||||
- **WHEN** пользователь перетаскивает полосу прокрутки в середину, а затем в самый конец списка
|
||||
- **THEN** в видимой области сначала могут быть заглушки, затем появляются строки с теми номерами по порядку, что и в полном списке, а последняя строка списка видна у нижнего края
|
||||
|
||||
#### Scenario: Память не растёт при прокрутке до конца
|
||||
- **WHEN** пользователь прокручивает лист RF «все» до конца и обратно
|
||||
- **THEN** число строк с данными, которые экран держит в памяти, не превышает предела (число страниц кэша × размер страницы)
|
||||
|
||||
### Requirement: Поиск и колоночные фильтры через сервер
|
||||
Изменение строки поиска (после существующей задержки ввода 300 мс) и изменение колоночного фильтра «Вид сметы», «Направление» или «ССП» SHALL перезапрашивать с сервера страницы видимой области и варианты фильтров, если по текущим году и ССП/РФ данные уже загружены. Если данные не загружены, запросов нет, как и сейчас. До прихода ответа экран SHALL показывать прежние строки. Ответ на устаревший запрос (после него условия уже поменялись) SHALL NOT попадать на экран. Варианты каждого колоночного фильтра SHALL совпадать с теми, что экран показывал до изменения: по строкам, найденным поиском и отобранным фильтрами двух других колонок, с числом строк у каждого варианта, без пустых значений, в прежнем порядке сортировки.
|
||||
|
||||
#### Scenario: Поиск
|
||||
- **WHEN** данные загружены и пользователь вводит «аренда» в поле поиска
|
||||
- **THEN** через 300 мс после последнего нажатия экран запрашивает строки и варианты с этим поиском и показывает тот же набор строк, что до изменения
|
||||
|
||||
#### Scenario: Варианты фильтра зависят от поиска и других фильтров
|
||||
- **WHEN** задан поиск и выбран фильтр «Вид сметы»
|
||||
- **THEN** в фильтрах «Направление» и «ССП» перечислены значения только из найденных строк этого вида сметы, с числами строк, а в фильтре «Вид сметы» — значения найденных строк без учёта его собственного выбора
|
||||
|
||||
#### Scenario: Быстрая смена условий
|
||||
- **WHEN** пользователь вводит поиск и, не дожидаясь ответа, выбирает колоночный фильтр «Направление»
|
||||
- **THEN** на экране остаются строки, отвечающие обоим условиям, а ответ на первый запрос не показывается
|
||||
|
||||
### Requirement: Счётчик «Найдено N из M»
|
||||
Подпись «Найдено N из M строк» SHALL вести себя как до изменения:
|
||||
- N — число строк, найденных поиском, без учёта колоночных фильтров;
|
||||
- M — число всех строк по текущим году и ССП/РФ;
|
||||
- подпись видна, когда данные загружены, загрузка по «Загрузить»/«Обновить» не идёт, и N ≠ M;
|
||||
- числа форматируются `ru-RU`.
|
||||
|
||||
#### Scenario: Колоночный фильтр не меняет счётчик
|
||||
- **WHEN** загружено 5 563 строки, поиск находит 300, и пользователь выбирает фильтр «Вид сметы», после которого видно 120 строк
|
||||
- **THEN** подпись остаётся «Найдено 300 из 5 563 строк»
|
||||
|
||||
### Requirement: Вкладки и обновление
|
||||
Возврат на ранее загруженную вкладку SHALL показывать её строки, как до изменения. Запрос к серверу допускается только за страницами, которых нет в ограниченном кэше вкладки. «Обновить» SHALL перезапрашивать данные текущей вкладки с сервера. Смена года или ССП/РФ, как и сейчас, требует нажать «Загрузить». Свод 2 SHALL NOT сохранять полные ответы в общем кэше сводов. Поведение свода 1 не меняется.
|
||||
|
||||
#### Scenario: Переключение вкладок
|
||||
- **WHEN** загружены «ССП» и «РФ» при прокрутке в начале, пользователь возвращается на «ССП»
|
||||
- **THEN** строки «ССП» видны сразу, без запроса страниц
|
||||
|
||||
#### Scenario: Обновить
|
||||
- **WHEN** пользователь нажимает «Обновить»
|
||||
- **THEN** экран заново запрашивает варианты фильтров и страницы видимой области и показывает актуальные данные
|
||||
|
||||
### Requirement: Ошибки загрузки
|
||||
Если не удался запрос по «Загрузить», «Обновить», поиску или колоночному фильтру, экран SHALL показывать, как и при ошибке загрузки сейчас, сообщение об ошибке с кнопкой «Повторить». Если не удалась догрузка страницы при прокрутке, экран SHALL оставить на её месте заглушки, показать всплывающее уведомление и повторить запрос, когда эта область снова окажется в видимой зоне.
|
||||
|
||||
#### Scenario: Ошибка догрузки
|
||||
- **WHEN** запрос страницы при прокрутке завершился ошибкой 500
|
||||
- **THEN** уже показанные строки остаются, на месте страницы — заглушки, показано уведомление; при повторной прокрутке к этому месту запрос повторяется
|
||||
|
||||
### Requirement: Замеры производительности экрана
|
||||
Для GO и RF на масштабах 1 и 2 (роль dfip, CPU 1×, одни данные, один и тот же код сценариев для «до» — вершины AURORA-1842 — и «после») SHALL быть сняты и приведены в PR:
|
||||
- **память** (`perf/e2e/scenarios/svod2-memory.spec.ts`: GO «Все ССП/РФ» → «Загрузить» → RF «Все ССП/РФ» → «Загрузить» → GO, сборка мусора) — `heap_used_mb` в конечной точке;
|
||||
- **время до первых строк** — `first_rows_ms`, от «Загрузить» до 20 строк с данными, заглушки не считаются;
|
||||
- **шаг прокрутки** — `main_thread_ms_per_step` (масштаб 1) и доля кадров с заглушками.
|
||||
|
||||
Целевые значения:
|
||||
- память на масштабе 1 — не больше 30 % «до», на масштабе 2 — не больше 1,25 значения «после» на масштабе 1;
|
||||
- время до первых строк — не больше 50 % «до»;
|
||||
- шаг прокрутки — не больше 1,10 значения «до».
|
||||
|
||||
Цифры условием слияния не являются: недобор оформляется follow-up задачей.
|
||||
|
||||
#### Scenario: Замер памяти
|
||||
- **WHEN** `svod2-memory.spec.ts` выполнен для «до» и «после» на масштабах 1 и 2, по 3 повтора
|
||||
- **THEN** в PR приведены медианы `heap_used_mb` по точкам и их отношение к целевым значениям, недобор записан как follow-up
|
||||
|
||||
#### Scenario: Замер времени до первых строк и шага прокрутки
|
||||
- **WHEN** `scroll.spec.ts` с `PERF_TARGETS='svod/svod2_*'`, `PERF_ROLES=dfip`, `--grep-invert filter` выполнен для «до» и «после»
|
||||
- **THEN** в записях есть `first_rows_ms`, `main_thread_ms_per_step` и доля кадров с заглушками, а в PR приведено сравнение с целевыми значениями
|
||||
Loading…
x
Reference in New Issue
Block a user