feat(web): rank chat mentions by recency (#3099)
This commit is contained in:
@@ -0,0 +1,141 @@
|
||||
---
|
||||
created: 2026-08-27
|
||||
status: done
|
||||
requirements:
|
||||
- REQ-UI-COMPOSER-MENTION-RECENCY-001
|
||||
system_design:
|
||||
- ../../specs/ui/system-design/composer-mention-recency.md
|
||||
legacy_specs: []
|
||||
---
|
||||
|
||||
# Implementation Plan: Rank Chat Mentions by Recency
|
||||
|
||||
## Overview
|
||||
|
||||
Add one browser-local MRU list for task, saved-prompt, and file selections in
|
||||
chat `@` menus. Apply the MRU rank after candidate lookup and before menu
|
||||
rendering. Record selection through the shared TipTap command path.
|
||||
|
||||
One vertical work order owns the storage helper, rank integration, selection
|
||||
wiring, unit tests, and desktop and phone E2E proof. These parts share the same
|
||||
identity and ordering contract, so a split creates no independent result.
|
||||
|
||||
## Scope
|
||||
|
||||
### In scope
|
||||
|
||||
- Persist 50 unique chat mention identities in newest-first order.
|
||||
- Rank recent task, saved-prompt, and returned file candidates before unselected
|
||||
candidates.
|
||||
- Use text relevance and stable source order after recency.
|
||||
- Preserve the Plan action's baseline position.
|
||||
- Record pointer, touch, Enter, and Tab selections through one command path.
|
||||
- Prove desktop reload persistence and phone touch parity.
|
||||
|
||||
### Out of scope
|
||||
|
||||
- Backend persistence or sync.
|
||||
- Candidate lookup changes or larger file-search results.
|
||||
- Recency for task creation, agent launch, `#`, or `/` menus.
|
||||
- New copy, settings, recent groups, frequency scores, or time decay.
|
||||
|
||||
## Technical approach
|
||||
|
||||
### Storage and rank
|
||||
|
||||
- Add `apps/web/lib/chat-mention-recency.ts` and its unit test.
|
||||
- Use the versioned key `kandev.chatMentionRecency.v1`.
|
||||
- Normalize unknown browser data before each read and write.
|
||||
- Key task and prompt entries by stable ID. Key file entries by workspace and
|
||||
path.
|
||||
- Keep one 50-entry newest-first list. Move a repeated selection to the front.
|
||||
- Export a pure rank helper that preserves current behavior when no history
|
||||
exists.
|
||||
|
||||
### Composer integration
|
||||
|
||||
- Pass `workspaceId` into `useMentionItems` in
|
||||
`apps/web/components/task/chat/tiptap-input.tsx`.
|
||||
- Replace the local text-only `filterItems` path with the shared rank helper.
|
||||
- Extend `MentionSuggestionCallbacks` with one selection callback.
|
||||
- Invoke that callback from the menu command closure after TipTap inserts the
|
||||
selected mention.
|
||||
- Keep `MentionMenu`, `PopupMenu`, selected-index reset, and entity-reference
|
||||
and slash-command plugins unchanged.
|
||||
|
||||
### Responsive contract
|
||||
|
||||
- Reuse the current popup on desktop and phone.
|
||||
- Keep the same listbox, row size, focus behavior, touch behavior, and scroll
|
||||
owner.
|
||||
- Do not add a mobile branch. Shared ranking produces the same order on both
|
||||
viewports.
|
||||
|
||||
## Tests
|
||||
|
||||
| Acceptance criterion | Evidence |
|
||||
| --- | --- |
|
||||
| `AC-UI-COMPOSER-MENTION-RECENCY-001.1` | Pure rank unit test and desktop E2E |
|
||||
| `AC-UI-COMPOSER-MENTION-RECENCY-001.2` | Unit test with a recent weaker text match |
|
||||
| `AC-UI-COMPOSER-MENTION-RECENCY-001.3` | Unit tests for baseline relevance and stable ties |
|
||||
| `AC-UI-COMPOSER-MENTION-RECENCY-001.4` | Selection-callback unit test and desktop/phone E2E |
|
||||
| `AC-UI-COMPOSER-MENTION-RECENCY-001.5` | Pure rank unit tests with empty and filtered queries |
|
||||
| `AC-UI-COMPOSER-MENTION-RECENCY-001.6` | Storage recovery unit tests and reload E2E |
|
||||
| `AC-UI-COMPOSER-MENTION-RECENCY-001.7` | Identity and workspace-scope unit tests |
|
||||
| `AC-UI-COMPOSER-MENTION-RECENCY-001.8` | Shared component tests and desktop/phone E2E |
|
||||
|
||||
Use Red-Green-Refactor. Run the new unit and E2E assertions before production
|
||||
changes and record their expected failures in the work-order results.
|
||||
|
||||
## E2E tests
|
||||
|
||||
- Add `apps/web/e2e/tests/chat/mention-recency.spec.ts` for desktop.
|
||||
- Seed two task candidates whose shared query gives different text scores.
|
||||
- Select the weaker text match through a unique query.
|
||||
- Reopen with the shared query and assert that selection recency wins.
|
||||
- Reload the page and assert that the same candidate remains first.
|
||||
- Add `apps/web/e2e/tests/chat/mobile-mention-recency.spec.ts` for
|
||||
`mobile-chrome`.
|
||||
- Repeat the rank proof with saved prompts and touch selection in the current
|
||||
mobile popup.
|
||||
- Remove disposable prompts and tasks through existing fixture cleanup or
|
||||
explicit `finally` blocks.
|
||||
|
||||
## Work orders
|
||||
|
||||
- [x] [Task 01: Rank chat mention suggestions](task-01-rank-chat-mention-suggestions.md)
|
||||
|
||||
## Verification results
|
||||
|
||||
- Red-Green-Refactor passed. The new selection-callback test failed before the
|
||||
callback wiring existed, and the new helper tests failed before the helper
|
||||
module existed.
|
||||
- Focused web unit tests passed: 2 files, 25 tests, including the filtered-query
|
||||
Plan-position regression found during PR fixup.
|
||||
- Managed production-build desktop and `mobile-chrome` E2E tests passed: 1 test
|
||||
each. Desktop coverage includes same-device reload persistence.
|
||||
- Web typecheck and targeted web lint passed with no errors or warnings.
|
||||
- Dependency installation passed with `pnpm install --frozen-lockfile`.
|
||||
|
||||
## Risks
|
||||
|
||||
- File recency can only reorder the current 20 file-search results. The helper
|
||||
must not reintroduce stale stored paths as live candidates.
|
||||
- The keyboard path calls the menu command directly. Recording only the React
|
||||
row click would miss Enter and Tab.
|
||||
- A comparator that reads mutable storage during pair comparisons can become
|
||||
inconsistent. Read and normalize the MRU list once per ranking operation.
|
||||
- Plan can move if it participates in the MRU comparator. Capture and restore
|
||||
its baseline index instead.
|
||||
- File paths can collide across workspaces. Include the workspace in file
|
||||
identities.
|
||||
|
||||
## Public documentation
|
||||
|
||||
None. The feature changes no command, configuration key, API, install flow, or
|
||||
public workflow.
|
||||
|
||||
## Decisions
|
||||
|
||||
No ADR is required. This local UI feature and its system design contain the
|
||||
selected ranking and persistence rules.
|
||||
@@ -0,0 +1,126 @@
|
||||
---
|
||||
id: "01-rank-chat-mention-suggestions"
|
||||
title: "Rank chat mention suggestions"
|
||||
status: done
|
||||
wave: 1
|
||||
depends_on: []
|
||||
plan: "plan.md"
|
||||
requirements:
|
||||
- REQ-UI-COMPOSER-MENTION-RECENCY-001
|
||||
acceptance_criteria:
|
||||
- AC-UI-COMPOSER-MENTION-RECENCY-001.1
|
||||
- AC-UI-COMPOSER-MENTION-RECENCY-001.2
|
||||
- AC-UI-COMPOSER-MENTION-RECENCY-001.3
|
||||
- AC-UI-COMPOSER-MENTION-RECENCY-001.4
|
||||
- AC-UI-COMPOSER-MENTION-RECENCY-001.5
|
||||
- AC-UI-COMPOSER-MENTION-RECENCY-001.6
|
||||
- AC-UI-COMPOSER-MENTION-RECENCY-001.7
|
||||
- AC-UI-COMPOSER-MENTION-RECENCY-001.8
|
||||
system_design:
|
||||
- ../../specs/ui/system-design/composer-mention-recency.md
|
||||
---
|
||||
|
||||
# Task 01: Rank Chat Mention Suggestions
|
||||
|
||||
## Summary
|
||||
|
||||
Add the bounded browser-local MRU helper and connect it to the shared TipTap
|
||||
chat mention path. Prove the same recency-first order on desktop and phone.
|
||||
|
||||
## In scope
|
||||
|
||||
- Add normalized storage, identity, update, and rank helpers.
|
||||
- Rank task, prompt, and returned file candidates by MRU position before text
|
||||
relevance.
|
||||
- Preserve the Plan action's baseline position.
|
||||
- Record pointer, touch, Enter, and Tab selections once.
|
||||
- Add focused unit, desktop E2E, and phone E2E tests.
|
||||
|
||||
## Out of scope
|
||||
|
||||
- Backend, API, database, boot-payload, or WebSocket changes.
|
||||
- New candidate sources or file-search limits.
|
||||
- Other composer types and suggestion triggers.
|
||||
- New copy or visual treatment.
|
||||
|
||||
## Acceptance
|
||||
|
||||
- With no valid history, the helper returns the current filtered order and Plan
|
||||
position.
|
||||
- After selection, that candidate ranks before stronger text matches and stays
|
||||
first after a same-device reload.
|
||||
- Desktop and phone use the same rank and preserve current insertion, focus,
|
||||
keyboard, touch, and popup behavior.
|
||||
|
||||
## Verification
|
||||
|
||||
```bash
|
||||
cd apps && pnpm install --frozen-lockfile
|
||||
cd apps/web && pnpm test -- \
|
||||
lib/chat-mention-recency.test.ts \
|
||||
components/task/chat/tiptap-suggestion.test.ts
|
||||
cd apps/web && pnpm e2e:run tests/chat/mention-recency.spec.ts
|
||||
cd apps/web && pnpm e2e:run --project mobile-chrome \
|
||||
tests/chat/mobile-mention-recency.spec.ts
|
||||
cd apps/web && pnpm run typecheck
|
||||
cd apps && pnpm --filter @kandev/web lint
|
||||
```
|
||||
|
||||
## Files likely touched
|
||||
|
||||
- `apps/web/lib/chat-mention-recency.ts`
|
||||
- `apps/web/lib/chat-mention-recency.test.ts`
|
||||
- `apps/web/components/task/chat/tiptap-input.tsx`
|
||||
- `apps/web/components/task/chat/tiptap-suggestion.tsx`
|
||||
- `apps/web/components/task/chat/tiptap-suggestion.test.ts`
|
||||
- `apps/web/e2e/tests/chat/mention-recency.spec.ts`
|
||||
- `apps/web/e2e/tests/chat/mobile-mention-recency.spec.ts`
|
||||
|
||||
## Dependencies
|
||||
|
||||
None.
|
||||
|
||||
## Risks
|
||||
|
||||
- The async file source can return after task and prompt candidates. Rank the
|
||||
completed candidate set once and preserve deterministic ties.
|
||||
- A storage error must not interrupt mention insertion.
|
||||
- A missing workspace must not give file paths global recency.
|
||||
- The test must prove recency over a stronger match, not only a source-order
|
||||
tie.
|
||||
|
||||
## Parallelism
|
||||
|
||||
`sequential`
|
||||
|
||||
## Inputs
|
||||
|
||||
- `docs/specs/ui/requirements/composer-mention-recency.md`
|
||||
- `docs/specs/ui/system-design/composer-mention-recency.md`
|
||||
- `apps/web/components/task/chat/tiptap-input.tsx`
|
||||
- `apps/web/components/task/chat/tiptap-suggestion.tsx`
|
||||
- `apps/web/lib/recent-tasks.ts` as the nearest browser-storage pattern
|
||||
- Existing composer mention unit and mobile popup E2E tests
|
||||
|
||||
## Results
|
||||
|
||||
Implemented device-local MRU ranking and shared TipTap selection recording for
|
||||
task, saved-prompt, and file mentions. Plan remains at its baseline position,
|
||||
invalid storage is ignored, and the same ranking path serves desktop and phone.
|
||||
|
||||
Red-Green-Refactor evidence:
|
||||
|
||||
- The selection-callback test failed before the shared callback was wired.
|
||||
- The helper tests failed before the new helper module was created.
|
||||
- Both suites passed after implementation.
|
||||
- PR fixup added a regression test for Plan's filtered baseline position. It
|
||||
failed before the fix and passed after the rank helper captured that index.
|
||||
|
||||
Verification:
|
||||
|
||||
- `cd apps && pnpm install --frozen-lockfile` passed.
|
||||
- `cd apps/web && pnpm test -- lib/chat-mention-recency.test.ts components/task/chat/tiptap-suggestion.test.ts` passed (2 files, 25 tests).
|
||||
- `cd apps/web && pnpm e2e:run tests/chat/mention-recency.spec.ts` passed (1 test).
|
||||
- `cd apps/web && pnpm e2e:run --project mobile-chrome tests/chat/mobile-mention-recency.spec.ts` passed (1 test).
|
||||
- `cd apps/web && pnpm run typecheck` passed.
|
||||
- `cd apps && pnpm --filter @kandev/web lint` passed.
|
||||
@@ -11,7 +11,7 @@ owners:
|
||||
|
||||
## Purpose
|
||||
|
||||
The UI system owns web presentation behavior for desktop and mobile surfaces.
|
||||
The UI system owns web presentation.
|
||||
|
||||
## Ownership
|
||||
|
||||
@@ -19,8 +19,8 @@ This system owns navigation, settings, boards, task/review surfaces,
|
||||
walkthroughs, chat controls, visual feedback, and responsive interaction
|
||||
contracts without backend-state ownership.
|
||||
|
||||
Controls that configure or display provider/task state remain owned by that
|
||||
system. The UI system owns only independent, reusable presentation contracts.
|
||||
Controls for provider/task state remain owned by that system.
|
||||
The UI system owns reusable contracts.
|
||||
|
||||
## Exclusions
|
||||
|
||||
@@ -55,6 +55,7 @@ system. The UI system owns only independent, reusable presentation contracts.
|
||||
- [Command-panel Sidebar Task Reveal](requirements/command-panel-sidebar-task-reveal.md)
|
||||
- [Compact Workflow Step Navigation](requirements/compact-workflow-step-navigation.md)
|
||||
- [Comment Markdown Rendering](requirements/comment-markdown.md)
|
||||
- [Mention recency](requirements/composer-mention-recency.md)
|
||||
- [Composer Suggestion Overlays](requirements/composer-suggestion-overlays.md)
|
||||
- [Context Compaction Count](requirements/context-compaction-count.md)
|
||||
- [Context Window Reset Freshness](requirements/context-window-reset-freshness.md)
|
||||
@@ -151,6 +152,7 @@ system. The UI system owns only independent, reusable presentation contracts.
|
||||
- [Agent Todo List Panel](system-design/agent-todo-list-panel.md)
|
||||
- [App Status Bar](system-design/app-status-bar.md)
|
||||
- [Changes File Row Containment](system-design/changes-file-row-containment.md)
|
||||
- [Mention recency](system-design/composer-mention-recency.md)
|
||||
- [Composer Suggestion Overlays](system-design/composer-suggestion-overlays.md)
|
||||
- [Compact Workflow Step Navigation](system-design/compact-workflow-step-navigation.md)
|
||||
- [Per-workflow column visibility on the kanban board System Design Part 1](system-design/board-step-visibility-filter-01.md)
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
---
|
||||
status: active
|
||||
system: ui
|
||||
created: 2026-08-27
|
||||
owners:
|
||||
- web
|
||||
---
|
||||
|
||||
# Composer Mention Recency Requirements
|
||||
|
||||
## Overview
|
||||
|
||||
Chat composers show tasks, saved prompts, files, and the Plan action in one
|
||||
`@` suggestion menu. The current menu ranks matches by text only. Users who
|
||||
mention the same items repeatedly must find them again for each message.
|
||||
|
||||
The UI system owns this behavior because the selection history is local
|
||||
presentation state. The task, settings, and workspace-file systems continue to
|
||||
own the available candidates.
|
||||
|
||||
## Terminology
|
||||
|
||||
- **Mention candidate:** A task, saved prompt, or file that the current chat
|
||||
composer can show in its `@` suggestion menu.
|
||||
- **Recent selection:** A mention candidate that the user selected from a chat
|
||||
composer on the current device.
|
||||
- **Baseline rank:** The existing text-match score and stable source order.
|
||||
|
||||
## Requirements
|
||||
|
||||
### REQ-UI-COMPOSER-MENTION-RECENCY-001: Rank chat mentions by recent selection
|
||||
|
||||
**Intent:** Make repeated mentions faster without changing candidate sources or
|
||||
the menu interaction.
|
||||
|
||||
**User story:** As a user, I want recent task, prompt, and file selections first,
|
||||
so that I can reuse them with less navigation.
|
||||
|
||||
#### Acceptance criteria
|
||||
|
||||
- **AC-UI-COMPOSER-MENTION-RECENCY-001.1:** When the `@` menu contains recent
|
||||
and unselected mention candidates, the menu shall show recent candidates
|
||||
before unselected candidates.
|
||||
- **AC-UI-COMPOSER-MENTION-RECENCY-001.2:** When two recent candidates are
|
||||
available, the menu shall show the most recently selected candidate first.
|
||||
Text-match quality shall rank candidates only after selection recency.
|
||||
- **AC-UI-COMPOSER-MENTION-RECENCY-001.3:** When two unselected candidates have
|
||||
different text-match quality, the menu shall preserve the existing text
|
||||
ranking. Equal candidates shall preserve the existing stable source order.
|
||||
- **AC-UI-COMPOSER-MENTION-RECENCY-001.4:** When the user selects a task, prompt,
|
||||
or file by pointer, touch, Enter, or Tab, it shall become the newest recent
|
||||
selection. Selecting it again shall move it to the front.
|
||||
- **AC-UI-COMPOSER-MENTION-RECENCY-001.5:** When recency changes other results,
|
||||
the Plan action shall keep the position that the baseline rank assigned for
|
||||
the current query. The Plan action shall not enter selection history.
|
||||
- **AC-UI-COMPOSER-MENTION-RECENCY-001.6:** When the user reloads Kandev on the
|
||||
same device, the bounded selection history shall continue to rank chat
|
||||
suggestions. A missing, malformed, or unavailable history shall restore the
|
||||
baseline rank without blocking selection.
|
||||
- **AC-UI-COMPOSER-MENTION-RECENCY-001.7:** Task and saved-prompt identities
|
||||
shall use their stable IDs. File identities shall include the workspace, so
|
||||
equal paths in different workspaces do not share recency.
|
||||
- **AC-UI-COMPOSER-MENTION-RECENCY-001.8:** Task chat, Quick Chat, and
|
||||
passthrough chat shall use the same ranking on desktop and phone. The current
|
||||
popup, keyboard navigation, focus, insertion, and touch behavior shall not
|
||||
change.
|
||||
|
||||
## Out of scope
|
||||
|
||||
- Changing task, saved-prompt, or workspace-file search sources and limits.
|
||||
- Showing a recent file that the current file search did not return.
|
||||
- Applying recency to task creation, agent launch, `#` references, or `/`
|
||||
commands.
|
||||
- Server storage, user sync, device sync, frequency scoring, or time decay.
|
||||
- Adding a recent label, group, setting, clear action, or other menu copy.
|
||||
@@ -0,0 +1,139 @@
|
||||
---
|
||||
status: current
|
||||
system: ui
|
||||
created: 2026-08-27
|
||||
requirements:
|
||||
- REQ-UI-COMPOSER-MENTION-RECENCY-001
|
||||
---
|
||||
|
||||
# Composer Mention Recency System Design
|
||||
|
||||
## Purpose and boundaries
|
||||
|
||||
This design adds device-local selection recency to the chat composer `@` menu.
|
||||
It does not change the candidate sources or their search limits.
|
||||
|
||||
The chat composer receives tasks from the Kanban store, prompts from settings,
|
||||
and files from `workspace.files.search`. The UI system ranks these candidates
|
||||
after each source returns them.
|
||||
|
||||
## Requirement mapping
|
||||
|
||||
| Requirement | Design section |
|
||||
| --- | --- |
|
||||
| `REQ-UI-COMPOSER-MENTION-RECENCY-001` | [Ranking](#ranking), [Selection flow](#selection-flow), [Persistence](#persistence), [Responsive behavior](#responsive-behavior) |
|
||||
|
||||
## Components and responsibilities
|
||||
|
||||
- A new `apps/web/lib/chat-mention-recency.ts` module owns storage parsing,
|
||||
bounded MRU updates, candidate identity, and deterministic ranking.
|
||||
- `useMentionItems` in `apps/web/components/task/chat/tiptap-input.tsx` keeps
|
||||
candidate loading in its current order. It applies the shared rank after task,
|
||||
Plan, prompt, and file candidates are available.
|
||||
- `createMentionSuggestion` in
|
||||
`apps/web/components/task/chat/tiptap-suggestion.tsx` records a selection in
|
||||
the same command path for pointer, touch, Enter, and Tab.
|
||||
- `MentionMenu` and `PopupMenu` keep their current rendering, focus, geometry,
|
||||
accessibility, and selected-index behavior.
|
||||
|
||||
## Data and contracts
|
||||
|
||||
The browser key is `kandev.chatMentionRecency.v1`. Its value is a JSON array in
|
||||
newest-first order. The module limits the normalized array to 50 unique entries.
|
||||
|
||||
Each entry has this shape:
|
||||
|
||||
```ts
|
||||
type ChatMentionRecentEntry = {
|
||||
kind: "task" | "prompt" | "file";
|
||||
id: string;
|
||||
workspaceId?: string;
|
||||
};
|
||||
```
|
||||
|
||||
Task and prompt entries use their stable IDs. File entries require the active
|
||||
workspace ID and use the returned path as `id`. The module rejects unknown
|
||||
kinds, empty IDs, and file entries without a workspace ID. It removes duplicate
|
||||
identities and keeps the newest valid entry.
|
||||
|
||||
The stored data contains no task title or prompt content. File entries contain
|
||||
the path that is necessary to match a later file result.
|
||||
|
||||
## Ranking
|
||||
|
||||
The rank function accepts the candidates, query, workspace ID, and normalized
|
||||
MRU entries. It uses this sequence:
|
||||
|
||||
1. Apply the existing text filter and score to create the baseline rank.
|
||||
2. Record the Plan action's index in that baseline rank, then remove the action.
|
||||
3. Put known MRU candidates before candidates that are not in the MRU list.
|
||||
4. For known candidates, use the newest-first MRU index.
|
||||
5. Use the existing text score after recency.
|
||||
6. Use the baseline index as the final stable tie-breaker.
|
||||
7. Insert the Plan action at its recorded baseline index.
|
||||
|
||||
If the MRU list is empty, this process returns the exact baseline order. A
|
||||
candidate outside the current source results does not enter the menu.
|
||||
|
||||
## Selection flow
|
||||
|
||||
1. The user enters an `@` query in a chat composer.
|
||||
2. `useMentionItems` collects current tasks, Plan, saved prompts, and file search
|
||||
results.
|
||||
3. The rank module reads and normalizes the current device history.
|
||||
4. The composer shows the ranked candidates and selects index zero.
|
||||
5. The user selects one candidate with pointer, touch, Enter, or Tab.
|
||||
6. The TipTap command inserts the mention by using the existing behavior.
|
||||
7. The selection callback moves the candidate identity to the MRU front.
|
||||
|
||||
The callback does not record Plan. It records each successful command path once.
|
||||
The next query or menu open reads the updated list.
|
||||
|
||||
## Failure and recovery
|
||||
|
||||
- If browser storage is unavailable, reads return an empty history and writes do
|
||||
nothing. Mention insertion continues.
|
||||
- If JSON parsing or entry validation fails, the module ignores invalid data and
|
||||
ranks with the remaining valid entries.
|
||||
- If a stored candidate no longer exists, it has no rank effect. New selections
|
||||
remove stale entries through the fixed limit.
|
||||
- If the workspace ID is unavailable, file candidates use baseline rank and file
|
||||
selections do not enter history. Tasks and prompts continue to use recency.
|
||||
|
||||
## Persistence
|
||||
|
||||
The browser owns the MRU list in `localStorage`. No backend API, database
|
||||
migration, Zustand slice, boot payload, or WebSocket event changes.
|
||||
|
||||
MRU order defines recency. The design does not use wall-clock timestamps,
|
||||
frequency counters, or decay. Clearing browser data resets the ranking.
|
||||
|
||||
## Responsive behavior
|
||||
|
||||
Desktop and phone use the same `TipTapInput`, rank function, and selection
|
||||
callback. The current contextual popup remains the presentation on both
|
||||
viewports.
|
||||
|
||||
This change does not add a surface, scroll owner, touch control, or breakpoint.
|
||||
`PopupMenu` remains the nearest shipped mobile exemplar. Existing viewport
|
||||
containment, 44-pixel rows, touch selection, and focus behavior remain valid.
|
||||
|
||||
A desktop E2E proves selection, primary recency rank, and reload persistence. A
|
||||
phone E2E proves the same rank after touch selection in the existing popup.
|
||||
|
||||
## Security
|
||||
|
||||
The history remains inside the Kandev browser origin. The module stores only
|
||||
candidate identities and file paths. It does not store prompt content, task
|
||||
titles, queries, or message text.
|
||||
|
||||
## Observability
|
||||
|
||||
No production telemetry is added. Unit tests cover storage recovery, scope,
|
||||
bounded updates, ranking priority, stable ties, and Plan position. Browser tests
|
||||
cover the user-visible desktop and phone flows.
|
||||
|
||||
## Related decisions
|
||||
|
||||
None. The requirement and this design preserve the local ranking choice. The
|
||||
feature does not create a cross-system architecture boundary.
|
||||
Reference in New Issue
Block a user