mirror of
https://gh-proxy.org/https://github.com/klinsmaya/multica.git
synced 2026-11-09 01:46:46 +08:00
* MUL-5824 fix(search): demote cancelled issues and projects below live work Cancelled work was outranking live work in both search and the @mention picker. Three separate causes: - Issue search ordered by relevance first and status second, so statusRank was inert across tiers: a cancelled issue matching a title exactly (tier 1) beat an in_progress issue that merely contained the phrase (tier 3). With LIMIT 20 applied after ordering, a workspace with many cancelled issues could push live work off the page entirely. - Project search had no status ranking at all, and the command palette renders projects above issues — so a cancelled project could be the first row of the whole result list. - The mention picker merged its local issue cache ahead of the server results and only then truncated to MAX_ITEMS, so a cached cancelled row both outranked and crowded out server-ranked live matches. Demote cancelled ahead of the relevance tiers in both query builders, and apply the same partition in the picker before its truncation. 'done' is untouched: finished work is still worth referencing, only cancelled work was thrown away. Exempt direct hits — an exact identifier or exact title means the searcher is targeting that one record, so it stays on top. Curated mention groups (current / recent / search) are exempt too: "Current" has to survive the truncation even when the issue being viewed is itself cancelled. Co-authored-by: multica-agent <[email protected]> * MUL-5824 fix(search): demote cancelled across issue+project result lists Follow-up to review on #6515. The per-type ranking landed server-side, but every client that shows issues and projects together aggregates two independently ranked responses — so a cancelled row from one still outranked a live row from the other: - The command palette and the mobile search screen render the whole Projects list before the whole Issues list, so one cancelled project was the first row of the result list next to a live issue. - The context @mention picker concatenates issues then projects and tags both 'search', while the client-side demotion only touched *ungrouped* cancelled issues. Cancelled search results were exempt and cancelled projects never participated at all. Move the partition to the aggregation point and make it cross-type. New shared helper @multica/core/search/cancelled-rank does one stable partition over both types, preserving the server's relative order on each side and mirroring the server's direct-hit exemption (exact identifier, bare number, exact title). All three consumers now render live projects, then live issues, then one trailing Cancelled section. A single trailing section is the only arrangement in which no cancelled row of either type can precede a live row of the other, and because it runs before truncation the cancelled tail is what gets dropped rather than a live row. The mention picker keeps its Current / Recent exemptions: those are explicit context, and "Current" has to survive truncation even when the issue on screen is itself cancelled. Mobile's row builder moved to apps/mobile/lib/search-rows.ts so the ordering is testable without mounting the screen. Also corrects the include_closed note in search_cancelled_rank_test.go: the mobile mention picker sends include_closed=false, so it never sees cancelled issues at all. Tests: mixed issue/project regressions for the palette (3), the context mention picker (4), the mobile row builder (6), and the shared helper (9). Each was confirmed to fail with the partition neutralised. Co-authored-by: multica-agent <[email protected]> * MUL-5824 fix(mention): pin cancelled direct hits above the truncation Second review round on #6515. The mention picker only exempted the curated Current / Recent groups, so a cancelled issue or project the user had typed out in full was still demoted — contradicting the direct-hit rule the backend and the other two search surfaces already share. The picker now applies that same query-aware rule via isIssueDirectHit / isProjectDirectHit: exact identifier, bare number, or full title for issues, and full title for projects. Both the partition and groupItems() take the query so they cannot disagree about which rows are exempt. Exemption alone was not enough. slice(0, MAX_ITEMS) runs on the merged list, so a direct hit behind a full window of cached candidates was still cut — a stale "row is still listed" claim in the old comment. The partition is now three tiers, pinned → live → cancelled, where pinned holds curated context plus direct hits. This mirrors the server, which already ranks direct hits first, and makes "Current survives the truncation" structural rather than incidental. isIssueDirectHit now takes all fields optional and derives the number from the identifier when `number` is absent, which is what lets the picker share the rule: its rows carry the identifier in `label` and the title in `description`, with no number field. An explicit `number` still wins if both are present. Tests: 5 mention regressions (exact identifier, bare number, project full title, direct hit visible behind 20 live candidates, and a partial match that must still be demoted) plus 3 helper cases for the identifier-derived number. Verified the four ordering tests fail with the exemption reverted, and that three of them still fail with exemption but no pinning — so the pinning tier is load-bearing, not belt-and-braces. Co-authored-by: multica-agent <[email protected]> --------- Co-authored-by: Lambda <[email protected]> Co-authored-by: multica-agent <[email protected]> Co-authored-by: Eve <[email protected]>