rowboatlabs / rowboatlabs/rowboat

Home suggestion tray re-shows the same (declined/dismissed) suggestion

Open
#830 2 comments 0 reactions 0 assignees View on GitHub
bug help wanted
Dominant language
TypeScript
Stars
17.6k
Forks
1.7k
Avg merge
11h 37m
Merged PRs (30d)
173

Description

## Summary
On the Home to-do surface, a suggestion that was already declined/dismissed (or already accepted) can reappear in the suggestion tray on a later planner run instead of staying permanently filtered out.

## Where this lives in code (found on `origin/feat/todo-homepage-v2` / `origin/fix/todo-home-polish` — not on `main` yet)
- `apps/x/apps/renderer/src/components/todo-view.tsx:1123` — stores `suggestions` state; `:1209-1214` loads them via `todo:get`; `:1334-1352` accept/decline handlers; `:1915-1948` renders the suggestion tray.
- `apps/x/apps/main/src/ipc.ts:2656-2686` — exposes `todo:get`, `todo:acceptSuggestion`, `todo:declineSuggestion`; `:2796-2805` records dismissal of accepted proposed items.
- `apps/x/packages/core/src/runtime/tools/domains/todo.ts:47-78` — implements the `todo-propose` tool used by the planner.
- `apps/x/packages/core/src/todo/planner-memory.ts:71-96` — records planner feedback and builds "sticky dismissed" keys; `:128-143` dedupes against the current `todo/suggestions.md`.
- `apps/x/packages/core/src/todo/fileops.ts:35-37` — normalizes suggestion keys (lowercase + whitespace collapse only); `:305-314` accepts a suggestion into `todo.md`.

## Root cause hypothesis
1. Decline/dismiss signals are recorded fire-and-forget in the IPC layer (`void recordPlannerSignal(...)` at `ipc.ts:2684` and `:2802`). If a planner run happens immediately after a decline, or the app is closed/crashes right after, the write can be missed and the same suggestion gets proposed again.
2. `planner_feedback.json` caps stored signals at 200 — older dismissed keys can age out and silently lose their "sticky dismissed" protection.
3. `normalizeKey` (fileops.ts:35-37) only lowercases and collapses whitespace. Any trivial rewording or punctuation change from the planner produces a different key, bypassing dedupe even though it's semantically the same suggestion the user already declined.

## Repro steps
1. On the Home to-do surface, trigger a suggestion (click "Suggest" / let the planner run).
2. Decline one of the suggestions.
3. Immediately trigger another planner run (click "Suggest" again, or restart the app shortly after declining).
4. Observe that the same suggestion — or a trivially reworded version of it — reappears in the tray instead of staying filtered out.

## Suggested fix directions
- Await `recordPlannerSignal` (or otherwise make the dismissal write synchronous/durable) before the IPC call resolves, so a dismiss is guaranteed to be persisted before the next planner run can start.
- Don't cap dismissed/sticky keys at a fixed count that discards old entries, or otherwise separate "sticky dismissed" storage from the general feedback signal log so it doesn't age out.
- Make `normalizeKey` more robust to punctuation/light rewording (e.g. strip punctuation, or use a fuzzy/substring match) so a re-generated suggestion with the same intent still matches a previously dismissed one.

_Note: the affected code appears to live on branches `feat/todo-homepage-v2` / `fix/todo-home-polish`, not yet on `main`._

Contributor guide

No contributing guide indexed for this repository

Research direction

Start by tracing the decline flow in `apps/x/apps/renderer/src/components/todo-view.tsx` and `apps/x/apps/main/src/ipc.ts`, then follow dismissal persistence and deduplication through `apps/x/packages/core/src/todo/planner-memory.ts` and `fileops.ts`. Check how the planner feedback cap and `normalizeKey` relate to the repro before choosing among the suggested fix directions. Done means a declined or dismissed suggestion stays filtered out on subsequent planner runs, including after restart and for the described trivial rewording.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
full-stack
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.