feat: add versioned search API contract #17
Reference in New Issue
Block a user
Delete Branch "feature/search-api-contract"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Выполняет этап API roadmap: stdlib HTTP API v1 c OpenAPI, поиском, фильтрами, серверной пагинацией/сортировкой/подсветкой и просмотром нормализованных документов и редакций. Версия backend 0.7.0; тесты 17/17.
Blocking findings:
backend/search/api.py:openapi()не является валидным OpenAPI 3.0.3: у каждого Operation Object отсутствует обязательное полеresponses(включая пустыеGET {}). Добавьте описанные схемы успешных и ошибочных ответов; иначе frontend-клиент не может опираться на контракт./search/filtersне выполняет этап roadmap «справочники v1»: возвращаетcodeиlabelкак одно динамическое значение из индекса, без стабильных кодов и RU/KY подписей. Кроме того,doc_countсчитает фрагменты/редакции, а не документы из выдачи. Нужны утверждённые versioned catalogs и агрегирование по документам/актуальной редакции./searchиндексирует все редакции и делаетcollapseтолько поdocument_code; поэтому hit (и полеedition) может быть из устаревшей редакции, если она совпадает лучше. Это противоречит требованию API выдавать актуальный документ. Нужен явный признак/фильтр текущей редакции либо удаление старых редакций из search alias, плюс интеграционный тест на этот случай.Полный набор unit-тестов проходит (17/17), но перечисленные сценарии им не покрыты. Verdict: blocking.
Re-review commit
0bef90d: previous finding about stale editions is resolved in implementation (is_current_editionis indexed and/searchfilters it). Test suite passes 18/18.Blocking findings remain:
OpenAPI is still invalid: path templates
/documents/{code}and/documents/{code}/editions/{edition}have no requiredin: path,required: trueparameter definitions forcode/edition. OpenAPI requires every templated path variable to be declared./search/filtersstill does not provide the roadmap’s stable catalog code:codeis the selected language label (item["key"][0/1]), so the same value changes fromЗаконtoМыйзамwithlanguage. 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.Pagination allows
pageup to 1,000,000 while it usesfrom; the default OpenSearchindex.max_result_windowis 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
9b629d9: previous blockers for OpenAPI path parameters andmax_result_windoware resolved. The suite passes 18/18 plus one optional local-OpenSearch integration test is present (skipped here becauseAKYLDASH_OPENSEARCH_URLis unset).Blocking findings remain:
backend/search/api.py:catalog_code()is not a stable catalog ID: it is a reversible serialization of the current RU/KY labels, andcatalog_label()accepts any syntactically valid serialized label pair. A label correction/retranslation changes the publiccode, 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.Backend version is
0.7.1in executable code and root/backend READMEs, but several changed project docs still publish0.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
0ef6ad4: blocking.docs/product/search-catalog-v1.mddefines intended IDs, but the API still does not use them:catalog_code()serializes current RU/KY labels andcatalog_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 promised400for 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
Authoritiespaths to the nine groups. Current normalized/indexed data preserves source labels/paths verbatim. In particular, a group ID such asparliamentcannot 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
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 version0.7.1are 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.
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.