docs(openspec): aurora-1843 — без ограничения длины поиска и фильтров (#22 отменено)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Andrey Epifancev 2026-10-28 20:49:25 +04:00
parent 9d68cd5e1a
commit 48f422df3a
2 changed files with 14 additions and 10 deletions

View File

@ -150,10 +150,10 @@
| параметр | тип | ограничение |
|---|---|---|
| `view` | `Literal["full","compact"] \| None` | |
| `search` | `str \| None` | `max_length=1000` |
| `smeta_type` | `str \| None` | `max_length=1000` |
| `smeta_direction` | `str \| None` | `max_length=1000` |
| `org_name` | `str \| None` | `max_length=1000` |
| `search` | `str \| None` | без ограничения длины |
| `smeta_type` | `str \| None` | без ограничения длины |
| `smeta_direction` | `str \| None` | без ограничения длины |
| `org_name` | `str \| None` | без ограничения длины |
Значения фильтров — свободные строки, а не перечисления: семантика `equals` (регистр и пробелы по краям не важны) принимает и «кв», и «КВ ». Неизвестное значение даёт 0 строк, как на экране.
@ -442,7 +442,7 @@ PR создаются по готовности, merge — по команде
- Совместимость с PG15.12 — отдельный шаг плана «проверка контроллером», контейнер `dfip-pg15`, порт 55434.
**Фаза 1, `api/tests/unit`:**
- валидация (по образцу `test_query_validation.py`): 422 на `search`/фильтры длиннее 1000 и на прежние невалидные параметры;
- валидация (по образцу `test_query_validation.py`): 422 на прежние невалидные параметры; `search` и фильтры длиной 5000 символов дают 200 (без ограничения длины);
- сервис:
- `_allowed_org_ids` применяется к страницам и вариантам;
- пустое пересечение даёт пустой ответ без SQL;
@ -624,6 +624,6 @@ PR создаются по готовности, merge — по команде
21. **2026-10-28 — значения для поиска строятся теми же выражениями, что `data` ответа (`header`, `contract_summary`, `contract_detail` листа), объединяются `jsonb ||` (перекрытие как у JS-спреда), числа приводятся к тексту функцией `svod2_js_number_text` (правила `Number::toString` поверх кратчайшей записи `float8`), обрезка — по набору пробельных символов ECMAScript.**
Обоснование: решение человека 9 — точное повторение `matchesSearch`.
Цена ошибки: если есть расхождение, оно ловится оракулом Node на данных стенда до слияния.
22. **2026-10-28 — ограничение длины `search` и значений фильтров — 1000 символов (422).**
Обоснование: защита от очень длинных URL. На экране ограничения нет, но поиск длиннее 1000 символов нереалистичен.
Цена ошибки: пользователь с таким запросом увидит ошибку вместо пустого результата. Снять ограничение — одна строка.
22. **2026-10-28 — ~~ограничение длины `search` и значений фильтров — 1000 символов (422)~~. Отменено контроллером 28.10: противоречит решению человека 9 («поведение абсолютно такое же»).**
Новая формулировка: API не ограничивает длину `search` и значений фильтров и не отвечает ошибкой из-за длины; длинный запрос даёт тот же результат, что на экране (совпадения есть или нет). Защита от злоупотребления — только невидимая пользователю: общий предел длины строки запроса у веб-сервера (uvicorn/h11 и прокси платформы, порядка килобайт и выше) остаётся как есть, отдельного предела в API не вводим.
Цена ошибки: очень длинный URL (десятки КБ) может упереться в предел прокси до приложения — на экране это нереалистичный ввод; если понадобится, фронт переведёт запросы на POST — полдня.

View File

@ -45,7 +45,7 @@
4. Значения берутся такими, какими они приходят в ответе этого листа. Например, на листе RF `contract_detail.expenses_q1..4` — это значения ответа (`COALESCE` договора и ЦКК).
5. Приведение к нижнему регистру SHALL NOT зависеть от локали базы данных. Для латиницы ASCII и кириллицы (включая Ё и буквы U+0400–U+042F, U+0490) результат SHALL совпадать с `toLowerCase()`.
Поиск сочетается с остальными условиями по «И». `search` длиннее 1000 символов SHALL отклоняться с 422.
Поиск сочетается с остальными условиями по «И». Длина `search` API не ограничивает: любой запрос даёт тот же результат, что поиск экрана (совпадения есть или их нет), без ошибки.
#### Scenario: Поиск без учёта регистра по кириллице независимо от локали
- **WHEN** в данных есть строка с `header.name = «Аренда помещения»`, база работает с `LC_CTYPE=C` или `en_US.utf8`, и выполняется запрос с `search=аРЕНДА`
@ -63,6 +63,10 @@
- **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`
@ -72,7 +76,7 @@
- **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 сужать выборку. Параметры длиннее 1000 символов SHALL отклоняться с 422. Все условия, включая `org_ids` и `search`, сочетаются по «И». `org_ids`, как и раньше, пересекается с организациями, разрешёнными пользователю.
Параметры `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=КВ`