Skip to content

Resolve recurrence series refs from search - #14

Merged
raine merged 2 commits into
raine:mainfrom
seungjuchoi:search-recurrence-series-refs
Aug 19, 2026
Merged

Resolve recurrence series refs from search#14
raine merged 2 commits into
raine:mainfrom
seungjuchoi:search-recurrence-series-refs

Conversation

@seungjuchoi

Copy link
Copy Markdown
Contributor

Problem

A recurring row advertises its series ref in the task list preview:

↻ RCR-NP3S · slot 2026-08-19 · weekdays · active

Every other command takes that ref — aven recur show RCR-NP3S resolves it, and resolve_recurrence_ref accepts it wherever a series is named. Search does not:

$ aven recur show RCR-NP3S
RCR-NP3S state=active rule="weekdays" ... title="오전 메일 확인"

$ aven search RCR-NP3S
                                  # nothing

Same in the TUI: typing a series ref you just read off the screen lands on the empty "no search results" view. In my own workspace 23 of 186 display refs were unsearchable, all of them series refs.

Root cause

The ref lane only ever had one identity to match against: score_ref_lane compares the query suffix to task.id, and gates on normalize_ref_query(task.project_prefix) == prefix. RCR is not a project prefix and a series id is not a task id, so a series ref fails both halves — no ref evidence, no candidates, empty result.

resolve_recurrence_ref already models the right shape: the hint must be absent or RCR, and the suffix matches recurrence_series.id.

Fix

Give the ref lane a second identity.

  • series_ref_suffix returns the suffix a series ref addresses — when the query names no prefix, or names RCR — and None when it names a project prefix.
  • load_series_ref_search_documents loads the occurrence tasks whose series id carries that suffix, under the same visibility rules the task ref lane already applies (ordinary_task_clause, so paused and archived projections stay out) and the same project/deleted scoping.
  • attach_recurrence_series_refs hangs each candidate's series id and series display ref off the document, reusing task_recurrence_summaries — the same call the preview path already makes.
  • score_series_ref_lane scores that identity; score_ref_lane keeps whichever of the two identities scores higher.

Recurrence grouping then collapses the matched occurrences into the single row callers expect, so search RCR-NP3S returns exactly the recurring row, and a bare suffix (NP3S) works too, matching how bare suffixes already address task ids.

Two things moved rather than changed: the scoring math is now score_ref_identity, shared by both lanes so a ref weighs the same either way (the task lane's behaviour, including the /WRONG-7KQ9 rejection, is unchanged), and SERIES_REF_PREFIX moved from operations::recurrence to recurrence, next to the display-ref formatter that mints it.

Test

search_resolves_recurrence_series_refs_to_their_occurrences creates a series and searches its ref three ways: qualified (RCR-…), bare suffix, and a wrong prefix (/APP-…) that must stay empty. It fails on main with 0 results.

cargo test, cargo clippy --all-targets, and cargo fmt --check pass. The 8 failures I see in cli_sync / cli_workspaces / cli_daemon_sync / cli_inference_errors are pre-existing on main — the exec_sql helper shells out to my system sqlite3, which has no fts5 module.

I also re-ran all 186 display refs in my own workspace through aven search; every one resolves now.

Independent of #13 (that one is the parser, this one is the lane), though both came out of the same "enter on a search result shows no results" report.

A recurring row shows its series ref (RCR-NP3S) in the task list preview,
and resolve_recurrence_ref accepts that ref everywhere else, but search
returned nothing for it: the ref lane only ever matched a task id, and the
prefix check demanded a project prefix, which RCR never is.

Give the ref lane a second identity to match. When the query names no
prefix or names RCR, load the occurrence tasks whose series id carries the
suffix — under the same visibility rules the task ref lane uses, so paused
and archived projections stay out — and score them against the series ref.
Recurrence grouping then collapses the occurrences into the single row the
caller expects.

The scoring math moves into score_ref_identity so both identities weigh a
ref the same way, and SERIES_REF_PREFIX moves next to the display-ref
formatter that mints it.
@seungjuchoi
seungjuchoi force-pushed the search-recurrence-series-refs branch from c488e90 to 85a6a1d Compare August 18, 2026 21:44
Bind the complete GLOB prefix pattern so SQLite can use the existing
(workspace_id, series_id, slot_on) primary key as a bounded series ID range.
The previous LIKE expression constrained the index only by workspace and
scanned every recurrence occurrence while filtering the prefix afterward.

This keeps the normalized Crockford Base32 matching behavior unchanged while
reducing the work performed by CLI and TUI live searches. There are no
breaking behavior changes.
@raine
raine merged commit 22b0c4b into raine:main Aug 19, 2026
2 checks passed
@raine

raine commented Aug 19, 2026

Copy link
Copy Markdown
Owner

Thanks again

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants