feat(search): reconcile /search to the shipped gateway shape (wave-search) - #56
Conversation
…arch) The public spec still documented the archived monolith's types/filters/page shape. The shipped route is namespace/topK hybrid search + /search/index + /search/analytics. This replaces the four stale paths (/search, /quick, /suggest, /semantic) with the shipped four, and rewrites SearchRequest/SearchResult to the route's actual contract.
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_01c6a919-4d19-4d42-b854-02d334205348) |
|
Warning Review limit reachedYou’ve reached a temporary PR review limit under our Fair Usage Limits Policy. Next review available in: 48 minutes Limit details: You’ve used all 1 included review currently available under your plan. You completed 104 included PR reviews in the past 7 days; at that activity level, included reviews refill at 1 review per hour. Your organization has reached its usage spending cap. Adjust your spending cap in the billing tab. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
Warning Billing warning: we have not been able to collect payment for this subscription for more than 72 hours. Please update the payment method or pay any pending invoices in Billing to avoid service interruption. Comment |
PR Summary by QodoAlign OpenAPI search contract with shipped wave-search gateway
AI Description
Diagram
High-Level Assessment
Files changed (1)
|
| SearchIndexRequest: | ||
| type: object | ||
| required: [id, namespace, text] | ||
| properties: | ||
| id: | ||
| type: string | ||
| namespace: | ||
| type: string | ||
| enum: [streams, users, clips, transcripts] | ||
| title: | ||
| type: string | ||
| text: | ||
| type: string | ||
| metadata: | ||
| type: object |
There was a problem hiding this comment.
⚠️ Bug: SearchIndexRequest requires id/namespace/text even in batch mode
SearchIndexRequest (openapi.yaml:2460-2478) marks id, namespace, and text as top-level required fields, but also exposes a docs array for batch upserts. A client submitting a pure batch request ({"docs": [...]}) would fail schema validation because the top-level required singular fields are absent, forcing batch callers to send dummy/duplicate top-level values alongside docs. Split this into two distinct request shapes (e.g. a oneOf/anyOf of a single-doc schema and a batch schema with only docs required), or drop top-level required and validate the single-vs-batch invariant in prose/description only.
Use oneOf to model single-doc vs batch as mutually exclusive valid shapes:
SearchIndexRequest:
oneOf:
- $ref: '#/components/schemas/SearchIndexDoc'
- type: object
required: [docs]
properties:
docs:
type: array
items:
$ref: '#/components/schemas/SearchIndexDoc'
- Apply fix
Check the box to apply the fix or reply for a change | Was this helpful? React with 👍 / 👎
| generated_at: | ||
| type: string | ||
| format: date-time |
There was a problem hiding this comment.
💡 Quality: generated_at breaks camelCase convention used elsewhere
SearchAnalyticsResponse (openapi.yaml:2515-2517) introduces generated_at in snake_case, while every other timestamp field in the spec (createdAt, updatedAt, processingTimeMs) uses camelCase. Rename to generatedAt for consistency, since this isn't a documented passthrough field like the snake_case exception at line 1621.
Rename to camelCase to match the rest of the spec:
generatedAt:
type: string
format: date-time
- Apply fix
Check the box to apply the fix or reply for a change | Was this helpful? React with 👍 / 👎
| SearchHighlight: | ||
| type: object | ||
| properties: | ||
| field: | ||
| type: string | ||
| snippet: | ||
| type: string | ||
| positions: | ||
| type: array | ||
| items: | ||
| type: object | ||
| properties: | ||
| start: | ||
| type: integer | ||
| end: |
There was a problem hiding this comment.
💡 Quality: Orphaned schemas left over from removed search endpoints
SearchHighlight, SearchSuggestion, and SearchFacet (openapi.yaml:2534-2571 area) are no longer referenced anywhere after the monolith search paths and their response shapes (which used SearchFacet, SearchSuggestion, SearchHighlight) were removed, but the schema definitions were left in components/schemas. Delete these dead schemas to keep the spec matching only the shipped gateway contract, consistent with the PR's stated goal of not documenting capabilities the route doesn't serve.
Delete unused schemas:
# Remove the SearchHighlight, SearchSuggestion, and SearchFacet schema blocks entirely from components/schemas
- Apply fix
Check the box to apply the fix or reply for a change | Was this helpful? React with 👍 / 👎
|
Note Automatic reviews are paused because your team has used its included automatic processing for this billing period (headroom scales with your seat count). You can still comment "Gitar review" to run one anytime, and automatic reviews resume on their own by September 1. Add seats for more headroom. Code Review
|
| Compact |
|
Was this helpful? React with 👍 / 👎 | Gitar
There was a problem hiding this comment.
Risk: medium. Left a non-blocking comment and did not approve: Cursor Bugbot was present but skipped (usage limit / incomplete analysis). Cursor Security Agent passed with no findings; human review is needed. No reviewers were assigned.
Sent by Cursor Approval Agent: Pull Request Router and Approver
Code Review by Qodo
1. Batch indexing cannot validate
|
| items: | ||
| $ref: '#/components/schemas/SearchInsightRow' | ||
|
|
||
| SearchHighlight: |
There was a problem hiding this comment.
1. openapi.yaml exceeds 500 lines 📘 Rule violation ⚙ Maintainability
The touched OpenAPI source contains approximately 2,440 non-empty, non-comment lines, exceeding the 500-line maximum. Its size increases maintenance and review complexity.
Agent Prompt
## Issue description
The touched `openapi.yaml` contains approximately 2,440 non-empty, non-comment lines, exceeding the 500-line source-file limit.
## Issue Context
The OpenAPI contract currently combines all paths and component schemas in one 2,575-line source artifact. Extract path groups and schemas into externally referenced YAML modules while preserving the published bundled contract.
## Fix Focus Areas
- openapi.yaml[1099-1181]
- openapi.yaml[2364-2549]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
|
|
||
| SearchIndexRequest: | ||
| type: object | ||
| required: [id, namespace, text] |
There was a problem hiding this comment.
2. Batch indexing cannot validate 🐞 Bug ≡ Correctness
SearchIndexRequest unconditionally requires the single-document fields id, namespace, and text, so the advertised batch body containing only docs is rejected by validators and generated clients. The schema also fails to enforce the intended choice between one document and a batch.
Agent Prompt
## Issue description
`SearchIndexRequest` requires single-document fields even when callers submit the documented `docs` batch form. Model the request as mutually exclusive single-document and non-empty batch alternatives.
## Issue Context
The `/search/index` operation advertises support for one document or a batch, and `SearchIndexDoc` already describes each batch element.
## Fix Focus Areas
- openapi.yaml[1126-1136]
- openapi.yaml[2444-2458]
- openapi.yaml[2460-2478]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| SearchResponse: | ||
| type: object | ||
| properties: | ||
| results: |
There was a problem hiding this comment.
3. Successful payloads validate empty 🐞 Bug ≡ Correctness
SearchResponse and the new index, delete, and analytics response schemas have no required lists,
so {} validates as every documented 200 response despite descriptions promising results and
metadata, indexed count and IDs, delete status and ID, or insights. Generated SDKs consequently
expose every successful-response field as optional.
Agent Prompt
## Issue description
The new successful-response schemas allow empty objects because none declares its guaranteed top-level properties as required. Add `required` lists matching the fields always returned by the shipped gateway.
## Issue Context
The operation descriptions promise concrete response envelopes, and this repository supports generating SDK models directly from the specification.
## Fix Focus Areas
- openapi.yaml[1113-1118]
- openapi.yaml[1138-1143]
- openapi.yaml[1163-1168]
- openapi.yaml[1176-1181]
- openapi.yaml[2399-2425]
- openapi.yaml[2480-2532]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
Qodo FixerFound 3 findings, but none include a fix that can be applied automatically. |


The public OpenAPI spec still documents the archived monolith's search contract (POST /search with types/filters/page/sort, plus /search/quick, /search/suggest, /search/semantic). The gateway has shipped a different, richer contract (wave-search), and the spec now lies to any integrator.
What changes
Why
The servers base is already https://api.wave.online/v1, so /search in the spec IS /v1/search live. The hard gate for this reconcile is that the spec describes the shipped route only — no documented capability the route does not serve. The removed monolith paths (/quick, /suggest, /semantic) no longer exist on the gateway.
Next
After this merges, the gateway re-pins its vendored copy (vendor/api-spec/pin.json SHA bump + spec:sync) so the published bytes match — a separate gateway PR.
Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.Note
Medium Risk
Breaking contract change for anyone still using the documented monolith search API; spec-only but affects integrators and downstream gateway spec sync.
Overview
Aligns
openapi.yamlSearch with the shipped gateway (wave-search) so documented/v1/searchmatches production instead of the archived monolith.Paths: Removes
/search/quick,/search/suggest, and/search/semantic. Documents POST/search(hybrid dense+sparse RRF), POST/search/index, DELETE/search/index/{id}(requirednamespacequery), and GET/search/analytics. POST/searchnow documents 400 / 429 / 503 and returnsSearchResponseinstead of a paginated envelope with facets.Schemas:
SearchRequestis nowquery+ optionalnamespace+topK(no types/filters/sort/page).SearchResultis a fused hit (fusedScore,matchType, dense/sparse scores, metadata). AddsSearchResponse,SearchWebHit, index/delete/analytics request/response types, andSearchInsightRow. Legacy suggestion/facet-oriented search shapes are dropped from the documented contract (some unused component schemas may remain).Reviewed by Cursor Bugbot for commit 03bbb77. Bugbot is set up for automated code reviews on this repo. Configure here.