Inline code review polish:
- --filter is only meaningful in per-database mode (workspace search
doesn't accept Notion filter objects). Previously a user passing
--filter without --databases would have it silently parsed and
ignored. Now emit a stderr warning and clear the filter.
- cache_kwargs dict was built twice in run_search (once for cache_get,
once for cache_put). Build once before the rerank call.
30/30 tests still pass.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Builds a rerank prompt with title + flattened properties + excerpt for
each candidate, calls Claude, parses JSON, sorts by score descending,
takes top N. On any failure (LLM error, missing JSON, parse error,
non-list shape), falls back to candidates in input order with null
relevance/snippet.
4 tests: ordering, limit, parse-error fallback, exception fallback.
26 passing total.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Code review polish:
- Drop the unused `name` parameter from `_flatten_property` (it was
reserved for future per-property-name special-casing but never used).
- Add a regression test pinning that checkbox=False and number=0 are
preserved in the enriched output. The existing empty-value filter is
`if value not in (None, [], "")` which keeps falsy-but-meaningful
values, but the contract wasn't tested.
22/22 tests pass.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
For each candidate page, extract the title, flatten common property
types (status/select/multi_select/date/checkbox/number/url/etc.) to
display values, and fetch the first text-bearing block as a 200-char
excerpt. Empty excerpt is acceptable when the page has no leading text.
4 tests: title+properties, paragraph excerpt, empty fallback,
truncation. 21 passing total.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Code review caught that without exception handling around
notion.search() and notion.data_sources.query(), any transient API
hiccup (rate limit, 5xx, network blip) would crash the whole search
and lose candidates already accumulated from earlier variants/DBs.
Wrap both calls in try/except, mirror the resolver's pattern: stderr
warning + continue. Same query against another variant or another DB
still has a chance to succeed.
Also tightened response.get("results", []) → response.get("results")
or [] so a hypothetical {"results": null} response doesn't crash the
inner loop.
17/17 tests still pass.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
For each expanded query variant: hit Notion's workspace search OR
per-database data_sources.query (when --databases is specified).
Union and dedupe by page ID, cap at 30 candidates total. Filters out
non-page objects (databases) from workspace search results.
Property filters (--filter JSON) pass through to data_sources.query
when in per-database mode.
5 tests: workspace dedup, 30-cap, DB-mode dispatch, page-only filter,
property-filter passthrough. 17 passing total.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Code review polish:
- Add stderr warning for the fourth failure path (LLM returned valid
JSON but it's not a list-of-strings). Previously this fell back
silently, making debugging harder when Haiku produces unexpected
shapes.
- Drop unused f-string prefixes from two warnings (no interpolation).
- Type hint: Callable[..., str] = None → Optional[Callable[..., str]] = None
for strict type-checker compatibility.
12/12 tests still pass.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Generates up to 5 query variants (synonyms + cross-language KR↔EN) so
later Notion API search can union over them. Permissive failure modes:
LLM error or non-JSON response falls back to [original] with stderr
warning. Dedupes and caps variants.
4 tests: variants list, dedup+cap, JSON-parse fallback, exception
fallback. 12 passing total.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>