feat: add versioned search API contract #17

Merged
admin merged 7 commits from feature/search-api-contract into main 2026-08-25 05:35:55 +00:00
Owner

Выполняет этап API roadmap: stdlib HTTP API v1 c OpenAPI, поиском, фильтрами, серверной пагинацией/сортировкой/подсветкой и просмотром нормализованных документов и редакций. Версия backend 0.7.0; тесты 17/17.

Выполняет этап API roadmap: stdlib HTTP API v1 c OpenAPI, поиском, фильтрами, серверной пагинацией/сортировкой/подсветкой и просмотром нормализованных документов и редакций. Версия backend 0.7.0; тесты 17/17.
agent added 1 commit 2026-08-21 03:13:02 +00:00
Author
Owner

Blocking findings:

  1. backend/search/api.py:openapi() не является валидным OpenAPI 3.0.3: у каждого Operation Object отсутствует обязательное поле responses (включая пустые GET {}). Добавьте описанные схемы успешных и ошибочных ответов; иначе frontend-клиент не может опираться на контракт.

  2. /search/filters не выполняет этап roadmap «справочники v1»: возвращает code и label как одно динамическое значение из индекса, без стабильных кодов и RU/KY подписей. Кроме того, doc_count считает фрагменты/редакции, а не документы из выдачи. Нужны утверждённые versioned catalogs и агрегирование по документам/актуальной редакции.

  3. /search индексирует все редакции и делает collapse только по document_code; поэтому hit (и поле edition) может быть из устаревшей редакции, если она совпадает лучше. Это противоречит требованию API выдавать актуальный документ. Нужен явный признак/фильтр текущей редакции либо удаление старых редакций из search alias, плюс интеграционный тест на этот случай.

Полный набор unit-тестов проходит (17/17), но перечисленные сценарии им не покрыты. Verdict: blocking.

Blocking findings: 1. `backend/search/api.py:openapi()` не является валидным OpenAPI 3.0.3: у каждого Operation Object отсутствует обязательное поле `responses` (включая пустые `GET {}`). Добавьте описанные схемы успешных и ошибочных ответов; иначе frontend-клиент не может опираться на контракт. 2. `/search/filters` не выполняет этап roadmap «справочники v1»: возвращает `code` и `label` как одно динамическое значение из индекса, без стабильных кодов и RU/KY подписей. Кроме того, `doc_count` считает фрагменты/редакции, а не документы из выдачи. Нужны утверждённые versioned catalogs и агрегирование по документам/актуальной редакции. 3. `/search` индексирует все редакции и делает `collapse` только по `document_code`; поэтому hit (и поле `edition`) может быть из устаревшей редакции, если она совпадает лучше. Это противоречит требованию API выдавать актуальный документ. Нужен явный признак/фильтр текущей редакции либо удаление старых редакций из search alias, плюс интеграционный тест на этот случай. Полный набор unit-тестов проходит (17/17), но перечисленные сценарии им не покрыты. Verdict: blocking.
agent added 1 commit 2026-08-21 04:24:23 +00:00
Author
Owner

Re-review commit 0bef90d: previous finding about stale editions is resolved in implementation (is_current_edition is indexed and /search filters it). Test suite passes 18/18.

Blocking findings remain:

  1. OpenAPI is still invalid: path templates /documents/{code} and /documents/{code}/editions/{edition} have no required in: path, required: true parameter definitions for code/edition. OpenAPI requires every templated path variable to be declared.

  2. /search/filters still does not provide the roadmap’s stable catalog code: code is the selected language label (item["key"][0/1]), so the same value changes from Закон to Мыйзам with language. It cannot be a language-independent value that a client stores or passes back reliably. Define catalog IDs and make filters/search accept those IDs; retain RU/KY only as labels.

  3. Pagination allows page up to 1,000,000 while it uses from; the default OpenSearch index.max_result_window is 10,000. Requests beyond that window become upstream errors and are exposed as 502. Enforce the real bound (or use a cursor/search_after contract) and cover it.

The roadmap also requires integration checks against local OpenSearch; current tests mock every backend call, so they do not verify the mapping/current-edition filter/aggregations end-to-end. Verdict: blocking.

Re-review commit `0bef90d`: previous finding about stale editions is resolved in implementation (`is_current_edition` is indexed and `/search` filters it). Test suite passes 18/18. Blocking findings remain: 1. OpenAPI is still invalid: path templates `/documents/{code}` and `/documents/{code}/editions/{edition}` have no required `in: path`, `required: true` parameter definitions for `code`/`edition`. OpenAPI requires every templated path variable to be declared. 2. `/search/filters` still does not provide the roadmap’s stable catalog code: `code` is the selected language label (`item["key"][0/1]`), so the same value changes from `Закон` to `Мыйзам` with `language`. It cannot be a language-independent value that a client stores or passes back reliably. Define catalog IDs and make filters/search accept those IDs; retain RU/KY only as labels. 3. Pagination allows `page` up to 1,000,000 while it uses `from`; the default OpenSearch `index.max_result_window` is 10,000. Requests beyond that window become upstream errors and are exposed as 502. Enforce the real bound (or use a cursor/search_after contract) and cover it. The roadmap also requires integration checks against local OpenSearch; current tests mock every backend call, so they do not verify the mapping/current-edition filter/aggregations end-to-end. Verdict: blocking.
agent added 1 commit 2026-08-25 04:29:23 +00:00
Author
Owner

Re-review commit 9b629d9: previous blockers for OpenAPI path parameters and max_result_window are resolved. The suite passes 18/18 plus one optional local-OpenSearch integration test is present (skipped here because AKYLDASH_OPENSEARCH_URL is unset).

Blocking findings remain:

  1. backend/search/api.py:catalog_code() is not a stable catalog ID: it is a reversible serialization of the current RU/KY labels, and catalog_label() accepts any syntactically valid serialized label pair. A label correction/retranslation changes the public code, so clients cannot persist it across catalog data changes; it also means no defined v1 catalog exists. Define immutable IDs in the catalog/index and map those IDs to labels; validate filter values against that catalog.

  2. Backend version is 0.7.1 in executable code and root/backend READMEs, but several changed project docs still publish 0.7.0 (docs/README.md, docs/operations/project-status.md, and the modified document footers). This contradicts the required application-version display. Align the version references before merge.

Verdict: blocking.

Re-review commit `9b629d9`: previous blockers for OpenAPI path parameters and `max_result_window` are resolved. The suite passes 18/18 plus one optional local-OpenSearch integration test is present (skipped here because `AKYLDASH_OPENSEARCH_URL` is unset). Blocking findings remain: 1. `backend/search/api.py:catalog_code()` is not a stable catalog ID: it is a reversible serialization of the current RU/KY labels, and `catalog_label()` accepts any syntactically valid serialized label pair. A label correction/retranslation changes the public `code`, so clients cannot persist it across catalog data changes; it also means no defined v1 catalog exists. Define immutable IDs in the catalog/index and map those IDs to labels; validate filter values against that catalog. 2. Backend version is `0.7.1` in executable code and root/backend READMEs, but several changed project docs still publish `0.7.0` (`docs/README.md`, `docs/operations/project-status.md`, and the modified document footers). This contradicts the required application-version display. Align the version references before merge. Verdict: blocking.
agent added 1 commit 2026-08-25 04:35:24 +00:00
agent added 1 commit 2026-08-25 05:22:13 +00:00
Author
Owner

Re-review commit 0ef6ad4: blocking. docs/product/search-catalog-v1.md defines intended IDs, but the API still does not use them: catalog_code() serializes current RU/KY labels and catalog_label() accepts arbitrary serialized pairs. The document is not referenced by code, there is no mapping/index field for the listed type, status, or authority-group IDs, and the promised 400 for unknown IDs is therefore not enforced. This leaves the previous stable-catalog blocker unresolved.

The catalogue also makes unsupported factual promises: the repository contains no source-derived enumeration or normalization mapping proving the 27 document types, the three statuses, or assignment of concrete Authorities paths to the nine groups. Current normalized/indexed data preserves source labels/paths verbatim. In particular, a group ID such as parliament cannot filter a concrete authority path under the present mapping. Add the authoritative source/mapping and implement/cover the catalog contract, or narrow this document to a proposed product decision. Verdict: blocking.

Re-review commit `0ef6ad4`: **blocking**. `docs/product/search-catalog-v1.md` defines intended IDs, but the API still does not use them: `catalog_code()` serializes current RU/KY labels and `catalog_label()` accepts arbitrary serialized pairs. The document is not referenced by code, there is no mapping/index field for the listed type, status, or authority-group IDs, and the promised `400` for unknown IDs is therefore not enforced. This leaves the previous stable-catalog blocker unresolved. The catalogue also makes unsupported factual promises: the repository contains no source-derived enumeration or normalization mapping proving the 27 document types, the three statuses, or assignment of concrete `Authorities` paths to the nine groups. Current normalized/indexed data preserves source labels/paths verbatim. In particular, a group ID such as `parliament` cannot filter a concrete authority path under the present mapping. Add the authoritative source/mapping and implement/cover the catalog contract, or narrow this document to a proposed product decision. Verdict: blocking.
agent added 1 commit 2026-08-25 05:26:54 +00:00
Author
Owner

Re-review commit 2ef33c5: previous blocking findings #684/#720/#723 are resolved. The API validates immutable v1 catalog IDs and returns 400 for unknown values; exporter and strict index mapping persist catalog code fields; filter aggregations count current document codes; OpenAPI declares required path parameters; pagination stays below the OpenSearch result window. Catalog compatibility rules and version 0.7.1 are documented.

Checks: PYTHONPATH=backend python3 -m unittest discover -s backend -p 'test_*.py' -v — 19 passed, 1 optional integration skipped; AKYLDASH_OPENSEARCH_URL=http://127.0.0.1:9200 PYTHONPATH=backend python3 -m unittest backend/test_search_api_opensearch.py -v — passed against local OpenSearch.

Review completed without blocking findings.

Re-review commit `2ef33c5`: previous blocking findings #684/#720/#723 are resolved. The API validates immutable v1 catalog IDs and returns 400 for unknown values; exporter and strict index mapping persist catalog code fields; filter aggregations count current document codes; OpenAPI declares required path parameters; pagination stays below the OpenSearch result window. Catalog compatibility rules and version `0.7.1` are documented. Checks: `PYTHONPATH=backend python3 -m unittest discover -s backend -p 'test_*.py' -v` — 19 passed, 1 optional integration skipped; `AKYLDASH_OPENSEARCH_URL=http://127.0.0.1:9200 PYTHONPATH=backend python3 -m unittest backend/test_search_api_opensearch.py -v` — passed against local OpenSearch. Review completed without blocking findings.
agent added 1 commit 2026-08-25 05:32:28 +00:00
Author
Owner

Final re-review commit 0f309f3: changelog records the user-visible Search API v1 delivery and the complete PR remains correct. Previous blockers #684/#720/#723 remain resolved: immutable catalog IDs are mapped and validated, OpenAPI path parameters are declared, pagination stays within the OpenSearch window, and searches/aggregations use current editions.

Checks: PYTHONPATH=backend python3 -m unittest discover -s backend -p 'test_*.py' -v — 19 passed, 1 optional integration skipped; AKYLDASH_OPENSEARCH_URL=http://127.0.0.1:9200 PYTHONPATH=backend python3 -m unittest backend/test_search_api_opensearch.py -v — passed.

Review completed without blocking findings.

Final re-review commit `0f309f3`: changelog records the user-visible Search API v1 delivery and the complete PR remains correct. Previous blockers #684/#720/#723 remain resolved: immutable catalog IDs are mapped and validated, OpenAPI path parameters are declared, pagination stays within the OpenSearch window, and searches/aggregations use current editions. Checks: `PYTHONPATH=backend python3 -m unittest discover -s backend -p 'test_*.py' -v` — 19 passed, 1 optional integration skipped; `AKYLDASH_OPENSEARCH_URL=http://127.0.0.1:9200 PYTHONPATH=backend python3 -m unittest backend/test_search_api_opensearch.py -v` — passed. Review completed without blocking findings.
admin merged commit bb69ea54b7 into main 2026-08-25 05:35:55 +00:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: agent/akyldash#17