Fix search timeout, sort vocabulary, and metadata handling#557
Conversation
Review carefully before merging. Consider a major version bump. |
There was a problem hiding this comment.
Pull request overview
This PR fixes basecamp search behavior to avoid unbounded pagination timeouts, align --sort with current API vocabulary, and handle search metadata schema drift more gracefully while the pinned SDK lacks search filter fields.
Changes:
- Cap default search results at 20 unless
--allis used; validate--limit(> 0) and forbid--all+--limit. - Normalize
--sortvalues tobest_match(relevance) orrecency, rejecting unknown values. - Treat empty search metadata as a successful response with a notice (instead of a fatal error), and update docs/tests accordingly.
Tip
If you aren't ready for review, convert to a draft PR.
Click "Convert to draft" or run gh pr ready --undo.
Click "Ready for review" or run gh pr ready to reengage.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| skills/basecamp/SKILL.md | Updates the skill docs/examples for capped search defaults, new sort vocabulary, and metadata caveats. |
| internal/commands/search.go | Implements bounded default limit, sort normalization, explicit --project/--in rejection, and graceful metadata handling. |
| internal/commands/search_test.go | Adds regression tests for default cap vs --all, sort mappings, --limit validation, project rejection, and metadata schema drift. |
| e2e/smoke/smoke_misc_read.bats | Updates smoke test to expect search metadata success even when metadata is empty (schema drift). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
`basecamp search` could hang indefinitely and reported confusing sort options and a fatal metadata error. - Bound the default result set to 20. `--limit` still defaults to 0, but the SDK treats Limit==0 as "fetch every page" and follows Link-header pagination unbounded, which paginates for 90s+ on a broad query. Apply a default cap unless `--all` opts into an unbounded fetch. Error on `--limit 0`/negative and on `--all --limit` together. - Normalize `--sort` to relevance (best_match) or recency, mapping the deprecated created_at/updated_at aliases onto recency and rejecting unknown values. Pin best_match explicitly for deterministic output. - Reject explicit `--project`/`--in` with a clear message: the pinned SDK's SearchParams exposes only q/sort, so project scoping needs a later SDK release that absorbs bucket_ids[]. Ambient config projects are untouched. - Stop treating empty search metadata as fatal. /searches/metadata.json now returns recording/file search types and labels the SDK does not model, so an empty projects list is schema drift, not an error — return success with a notice instead.
6317039 to
731f11b
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 731f11bd9b
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Fixes #470
Refs #546
Problem
basecamp search "<query>" --jsonhangs indefinitely (tested to 90s), no results, no error.--projectis silently ignored, andbasecamp search metadatafails withError: Search meta….Root causes
Timeout (basecamp search timing out #470).
--limitdefaults to0; the SDK treats0as "fetch ALL" and follows Link-header pagination across every page unbounded (followPagination). A broad or blank search paginates for 90s+. Affects all output formats."Identical unrelated results" (search ignores query semantics and project filter #546) — already fixed upstream. The primary cause was old SDK GET requests carrying
Content-Type: application/json, which made BC3 discardqand every filter (SDK Add lineup list command #324, closed; BC3 #12361). The pinned SDK v0.8.0 sets that header only when the request has a body, so bodyless GETs like search no longer trip it, and BC3 already defaults blanksorttobest_match. The residual CLI defect was stale sort docs/vocabulary; unbounded pagination (cause 1) amplified any broad query into the timeout.--projectignored (search ignores query semantics and project filter #546) — SDK gap. The global--project/--inflag is accepted but never read. SDKSearchParams(v0.8.0, latest published) exposes onlyQ/Sort— nobucket_ids[]. BC3 #12361 is merged server-side, but no published SDK exposes the filters.search metadataerror (search ignores query semantics and project filter #546) — schema drift./searches/metadata.jsonnow returns recording/file search types (askey/valuepairs) plusdefault_*filter labels; the SDKSearchMetadatamodels onlyProjects, so the response deserializes to an emptyprojectsarray, which the CLI turned into a fatal error.Changes (CLI-only, this PR)
--allnor an explicit--limitis given.--all→ unbounded; explicit--limitmust be> 0;--all+--limittogether is a usage error. Regression tests prove a bare search returns 20 in one HTTP request while--alltraverses every page.--sortnormalizes torelevance(→best_match, pinned explicitly) orrecency(with deprecatedcreated_at/updated_ataliases mapped in); unknown values are rejected. BC3 treats any non-blank, non-best_matchsort as created-at descending, sorecencyworks today regardless of the search-filter release. Help and examples updated.--project(interim). Explicit--project/--inis rejected with a message pointing at the pending SDK release; ambient config projects are never rejected.Deferred to the post-SDK-bump follow-up (completes #546)
After
make bump-sdkto the release that absorbs the search filters/metadata: resolve--projectviaapp.Names.ResolveProject(ID or name) into the SDK's bucket-ID type, add--type/--since, expose the real metadata fields, drop the interim--projectrejection, thenFixes #546.SDK contract still missing
Tracked in the SDK's canonical gap doc
spec/api-gaps/search-filter-additions.md(stale — BC3 #12361 has since merged) and closed SDK #324. Missing from a published SDK:bucket_ids[],type_names[],creator_ids[],file_type,exclude_chat,since,best_match/recencysort, the metadatarecording_search_types/file_search_types(key/valuepairs) anddefault_creator_label/default_bucket_label/default_circle_label/default_file_type_label/default_type_labelfields, and thetimelines/searchescounterpart.Verification
bin/cifully green (fmt, vet, lint, unit + e2e BATS, naming, surface snapshot, skill-drift, SDK provenance, go mod tidy).grep 'replace' go.mod→ none. The metadata fixture mirrors bc3app/views/api/searches/metadata/index.json.jbuilder.