Skip to content

Fix search timeout, sort vocabulary, and metadata handling - #557

Merged
jeremy merged 1 commit into
mainfrom
fix/search-semantics-timeout
Jul 25, 2026
Merged

Fix search timeout, sort vocabulary, and metadata handling#557
jeremy merged 1 commit into
mainfrom
fix/search-semantics-timeout

Conversation

@jeremy

@jeremy jeremy commented Jul 22, 2026

Copy link
Copy Markdown
Member

Fixes #470
Fixes #546

Problem

Root causes

  1. Timeout (basecamp search timing out #470). --limit defaults to 0; the SDK treats 0 as "fetch ALL" and follows Link-header pagination across every page unbounded (followPagination). A broad or blank search paginates for 90s+. Affects all output formats.

  2. "Identical unrelated results" (search ignores query semantics and project filter #546) — fixed upstream. The primary cause was old SDK GET requests carrying Content-Type: application/json, which made BC3 discard q and every filter (SDK Add lineup list command #324, closed; BC3 #12361). The current SDK sets that header only when the request has a body, so bodyless GETs like search no longer trip it, and BC3 defaults blank sort to best_match. The residual CLI defect was stale sort docs/vocabulary; unbounded pagination (cause 1) amplified any broad query into the timeout.

  3. --project/filters ignored (search ignores query semantics and project filter #546). The global --project/--in flag was accepted but never read; --type/--creator/--since/--file-type did not exist. The SDK's SearchOptions now exposes the filter fields.

  4. search metadata shape (search ignores query semantics and project filter #546). /searches/metadata.json returns recording/file search types (as key/value pairs) plus default_* filter labels; the CLI needed to present the real fields and count them correctly.

SDK

The SearchOptions.{BucketIds,TypeNames,CreatorIds,FileType,ExcludeChat,Since} (plus deprecated singulars) and the real SearchMetadata (RecordingSearchTypes/FileSearchTypes as key/value pairs plus five Default*Label fields) ship in the SDK. This PR bumps the pin to the current SDK tip (a98f52fd3ddd), which additionally hardens the generated array query params (bucket_ids[]/type_names[]/creator_ids[]) to omit empty slices on the wire (basecamp-sdk #407/#410) — the public SearchService wrapper the CLI uses was already safe, so that guard is defense in depth. The wrapper owns bracket wire-encoding, so the CLI just sets the option fields. No new SDK service methods and no CLI surface change came with the bump.

Rebased onto main after #554 merged. #554 made a minimal metadata reshape as a side effect of its SDK bump; this PR supersedes that with the full #546 implementation (correct non-default counts, graceful empty, plus all the filter flags).

Changes

  • Bounded default (fixes basecamp search timing out #470). Default cap of 20 when neither --all nor an explicit --limit is given. --all → unbounded; explicit --limit must be > 0; --all + --limit together is a usage error. Regression tests prove a bare search returns 20 in one HTTP request while --all traverses every page.
  • Sort vocabulary (search ignores query semantics and project filter #546). --sort normalizes to relevance (→ best_match, pinned explicitly) or recency (with deprecated created_at/updated_at aliases mapped in); unknown values are rejected.
  • Full filter surface (completes search ignores query semantics and project filter #546). New flags:
    • --project/--in — resolved via app.Names.ResolveProject (ID or name) to bucket_ids[]. Only an explicit flag scopes; ambient config project stays ignored (search is account-wide).
    • --type — friendly aliases and canonical Keys through a dedicated table (todo, cardKanban::Card, file/uploadAttachment, pingCircle, check-inQuestion, eventSchedule::Entry, folderVault, chatChat::Transcript, forwardInbox::Forward, clientClient::Correspondence, …). Search uses a different type vocabulary than recordings, so this does not reuse normalizeRecordingType. Unknown values are rejected: BC3 silently discards an unrecognized type and returns unfiltered results.
    • --creator — resolved via app.Names.ResolvePerson (name/email/ID/me).
    • --file-type — case-normalized to BC3's case-sensitive Blob::TYPES (imageImage, …), so image does not silently disable the filter. Unknown values rejected.
    • --sincelast_7_days/last_30_days/last_90_days/last_12_months/forever (BC5-only; no BC4 equivalent). Unknown values rejected.
    • --exclude-chat.
    • Each filter is sent in both the plural (BucketIds/TypeNames/CreatorIds) and deprecated singular forms, so BC5 honors the plural while older clients fall back to the singular.
  • Real metadata (fixes search ignores query semantics and project filter #546 metadata). search metadata presents the real recording/file search types and default labels; the summary counts only selectable (non-default) options — the key:null "Everything"/"All files" default is excluded. Empty metadata is a graceful success, not an error.
  • Docs/snapshots. .surface, skills/basecamp/SKILL.md, API-COVERAGE.md, and the search-metadata smoke test updated.

Verification

bin/ci fully green (fmt, vet, lint, unit + e2e BATS, naming, surface snapshot, skill-drift, SDK provenance, go mod tidy). grep 'replace' go.mod → none. Tests cover project/creator resolution (bucket_ids[]+bucket_id, creator_ids[]+creator_id), the --type/--file-type/--since vocabularies (dual plural+singular wire forms, invalid values rejected before any request), and the real metadata shape (non-default counts).

Copilot AI review requested due to automatic review settings July 22, 2026 21:26
@github-actions github-actions Bot added commands CLI command implementations tests Tests (unit and e2e) skills Agent skills breaking Breaking change bug Something isn't working labels Jul 22, 2026
@github-actions

github-actions Bot commented Jul 22, 2026

Copy link
Copy Markdown

⚠️ Potential breaking changes detected:

  • Renaming of the '--sort' flag values: The flag previously allowed 'created_at' and 'updated_at', which are now treated as aliases for 'recency'. This could break scripts specifying the removed 'created_at' or 'updated_at' values.
  • Introduction of a default search limit of 20 results when neither '--all' nor '--limit' is specified. Previously, there was no default limit, so scripts relying on this behavior may receive fewer results.
  • Change in behavior of '--project/--in' flags: Any explicit use of these flags results in a usage error due to unsupported project-scoped searches.

Review carefully before merging. Consider a major version bump.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 --all is used; validate --limit (> 0) and forbid --all + --limit.
  • Normalize --sort values to best_match (relevance) or recency, 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.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 4 files

Re-trigger cubic

Copilot AI review requested due to automatic review settings July 22, 2026 22:48
@jeremy
jeremy force-pushed the fix/search-semantics-timeout branch from 6317039 to 731f11b Compare July 22, 2026 22:48

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

Comment thread internal/commands/search.go
Comment thread internal/commands/search.go Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread internal/commands/search.go
@jeremy jeremy added this to the v0.8.0 milestone Jul 22, 2026
Copilot AI review requested due to automatic review settings July 24, 2026 19:48
@jeremy
jeremy force-pushed the fix/search-semantics-timeout branch from 731f11b to fbeece9 Compare July 24, 2026 19:48
@github-actions github-actions Bot added sdk SDK wrapper and provenance docs deps and removed breaking Breaking change labels Jul 24, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 9 changed files in this pull request and generated 1 comment.

Comment thread internal/commands/search.go Outdated
Copilot AI review requested due to automatic review settings July 24, 2026 21:35
@jeremy
jeremy force-pushed the fix/search-semantics-timeout branch from fbeece9 to e20689e Compare July 24, 2026 21:35
@github-actions github-actions Bot removed sdk SDK wrapper and provenance deps labels Jul 24, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Comment thread internal/commands/search.go Outdated
Copilot AI review requested due to automatic review settings July 24, 2026 21:41
@jeremy
jeremy force-pushed the fix/search-semantics-timeout branch from e20689e to 3aa3516 Compare July 24, 2026 21:41

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Comments suppressed due to low confidence (1)

internal/commands/search.go:447

  • The metadata summary uses unconditionally plural "types", which produces ungrammatical output for singular counts (e.g., "1 recording types"). Consider pluralizing based on the count so the summary reads correctly for 0/1/N.
	recordingOptions := countSelectableTypes(metadata.RecordingSearchTypes)
	fileOptions := countSelectableTypes(metadata.FileSearchTypes)
	summary := fmt.Sprintf("Search filters: %d recording types, %d file types", recordingOptions, fileOptions)

Comment thread internal/commands/search_test.go Outdated
Copilot AI review requested due to automatic review settings July 24, 2026 21:47
@jeremy
jeremy force-pushed the fix/search-semantics-timeout branch from 3aa3516 to 9807123 Compare July 24, 2026 21:47

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated no new comments.

Copilot AI review requested due to automatic review settings July 25, 2026 04:01
@jeremy
jeremy force-pushed the fix/search-semantics-timeout branch from 9807123 to c386d62 Compare July 25, 2026 04:01
@github-actions github-actions Bot added sdk SDK wrapper and provenance deps labels Jul 25, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 9 changed files in this pull request and generated no new comments.

Bound the default search result set and wire the full filter surface into
basecamp search.

#470: --limit defaulted to 0, which the SDK treats as 'fetch every page' and
follows Link-header pagination unbounded, hanging 90s+ on a broad query. Apply
a default cap of 20 (--all restores unbounded; --all + --limit is a usage error).

#546: sort vocabulary and the previously-ignored project/type/metadata filters.
--sort normalizes to relevance (best_match) or recency. New filter flags:

  --project/--in   scope to a project (resolved to bucket_ids[])
  --type           filter by content type (todo, card, ping, chat, ...)
  --creator        filter by creator (name, email, ID, or me)
  --since          bound to a time range (BC5-only)
  --file-type      filter attachments (image, audio, video, pdf)
  --exclude-chat   drop chat/campfire results

Search uses a different type vocabulary than recordings (upload -> Attachment,
ping -> Circle, check-in -> Question, event -> Schedule::Entry, folder -> Vault,
chat -> Chat::Transcript, forward -> Inbox::Forward), so --type resolves through
a dedicated table and rejects unknown values rather than passing them through:
BC3 silently discards an unrecognized type and returns unfiltered results.
--file-type normalizes casing to BC3's case-sensitive Blob::TYPES membership so
'image' does not silently disable the filter. Each filter is sent in both the
plural (BucketIds/TypeNames/CreatorIds) and deprecated singular forms so BC5
honors the plural while older clients fall back to the singular.

search metadata now presents the real recording/file search types and default
labels; the summary counts only selectable (non-default) options — the
key:null 'Everything'/'All files' default is excluded. Empty metadata is a
graceful success, not an error.

The SearchOptions/SearchMetadata types come from the SDK. Bump the pin to the
current SDK tip (a98f52fd3ddd), which hardens the generated array query params
(bucket_ids[]/type_names[]/creator_ids[]) to omit empty slices on the wire
(basecamp-sdk #407/#410); the public SearchService wrapper the CLI uses was
already safe, so this is defense in depth. No new SDK service methods, no CLI
surface change.

Update .surface, SKILL.md, API-COVERAGE.md, and the search-metadata smoke test.
Copilot AI review requested due to automatic review settings July 25, 2026 04:13
@jeremy
jeremy force-pushed the fix/search-semantics-timeout branch from c386d62 to 26d0419 Compare July 25, 2026 04:13

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 9 changed files in this pull request and generated no new comments.

@jeremy
jeremy merged commit 23195d5 into main Jul 25, 2026
27 checks passed
@jeremy
jeremy deleted the fix/search-semantics-timeout branch July 25, 2026 04:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working commands CLI command implementations deps docs sdk SDK wrapper and provenance skills Agent skills tests Tests (unit and e2e)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

search ignores query semantics and project filter basecamp search timing out

2 participants