Skip to content

Lists S2: Projects app Lists tab UI (#2140) - #2379

Merged
jaylfc merged 4 commits into
devfrom
exec/tsk-zitqoj
Aug 13, 2026
Merged

Lists S2: Projects app Lists tab UI (#2140)#2379
jaylfc merged 4 commits into
devfrom
exec/tsk-zitqoj

Conversation

@jaylfc

@jaylfc jaylfc commented Aug 12, 2026

Copy link
Copy Markdown
Owner

CARD TITLE (intent, not commit subject): Lists S2: Projects app Lists tab UI (#2140)

Autonomous build of board card tsk-zitqoj.

Adds a Lists tab to the Projects workspace with a list rail showing all
project lists and an entries panel for the selected list. Entry rows
include a done checkbox, category chip, status pill (new=blue, seen=grey,
actioned=green, discuss=amber), a quick-add input with Enter-to-submit,
and an indicator to view the original text when it has been tidied.
Follows the Store/Images design bar pattern with rounded borders and
shell surface backgrounds.

Adds vitest tests covering quick-add creation, status pill rendering,
and done toggle behavior.

Files:
desktop/src/apps/ProjectsApp/ProjectLists.tsx | 314 +++++++++++++++++++++
desktop/src/apps/ProjectsApp/ProjectWorkspace.tsx | 8 +-
.../src/apps/ProjectsApp/ProjectsApp.module.css | 34 +++
.../ProjectsApp/tests/ProjectLists.test.tsx | 121 ++++++++
desktop/src/lib/projects.ts | 68 +++++
5 files changed, 542 insertions(+), 3 deletions(-)

Summary by CodeRabbit

  • New Features
    • Added a Lists tab to project workspaces.
    • Create, select, delete, and reorder project lists.
    • Add, update, complete, and delete list entries.
    • Manage entry categories and statuses, with original text available after edits.
    • Added responsive layouts for desktop and mobile screens.
  • Bug Fixes
    • Added clear loading, empty, submission, and error states.
  • Tests
    • Added coverage for list rendering, entry actions, statuses, and quick-add behavior.

Adds a Lists tab to the Projects workspace with a list rail showing all
project lists and an entries panel for the selected list. Entry rows
include a done checkbox, category chip, status pill (new=blue, seen=grey,
actioned=green, discuss=amber), a quick-add input with Enter-to-submit,
and an indicator to view the original text when it has been tidied.
Follows the Store/Images design bar pattern with rounded borders and
shell surface backgrounds.

Adds vitest tests covering quick-add creation, status pill rendering,
and done toggle behavior.
@qodo-code-review

Copy link
Copy Markdown

ⓘ Qodo reviews are paused because the subscription is no longer active. Ask your workspace admin to reactivate the subscription to resume reviews. Manage billing

@gitar-bot

gitar-bot Bot commented Aug 12, 2026

Copy link
Copy Markdown

Gitar is working

Gitar

@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@jaylfc, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 55 seconds

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 93324717-9ade-4750-8591-be75d1b0361d

📥 Commits

Reviewing files that changed from the base of the PR and between 7531a5f and 95465c0.

📒 Files selected for processing (6)
  • changelog.d/2379-projects-lists-tab.md
  • desktop/src/apps/ProjectsApp/ProjectLists.tsx
  • desktop/src/apps/ProjectsApp/ProjectWorkspace.tsx
  • desktop/src/apps/ProjectsApp/ProjectsApp.module.css
  • desktop/src/apps/ProjectsApp/__tests__/ProjectLists.test.tsx
  • desktop/src/lib/projects.ts
📝 Walkthrough

Walkthrough

The PR adds project-list and entry API types and methods. It adds a Lists tab to the project workspace with list selection, CRUD actions, status updates, completion toggles, original-text display, responsive layouts, and Vitest coverage.

Changes

Project Lists

Layer / File(s) Summary
Project list API contracts
desktop/src/lib/projects.ts
Adds ProjectList and ProjectListEntry types. Adds list and nested entry CRUD and reorder methods to projectsApi.lists.
List loading and mutations
desktop/src/apps/ProjectsApp/ProjectLists.tsx
Adds list and entry loading, creation, deletion, completion toggling, status updates, validation, error handling, and refresh behavior.
List and entry interface
desktop/src/apps/ProjectsApp/ProjectLists.tsx, desktop/src/apps/ProjectsApp/__tests__/ProjectLists.test.tsx
Renders list and entry panels with keyboard controls, status badges, original-text disclosure, submission states, and tests for the main interactions.
Workspace tab and responsive layout
desktop/src/apps/ProjectsApp/ProjectWorkspace.tsx, desktop/src/apps/ProjectsApp/ProjectsApp.module.css, changelog.d/2379-projects-lists-tab.md
Adds the Lists tab to desktop and mobile navigation. Renders ProjectLists, adds responsive rail and entry-panel layouts, and records the feature in the changelog.

Estimated code review effort: 4 (Complex) | ~45 minutes

Mergeability Score: 🟡 Moderate · up to 2bd3d

The Lists tab can show or mutate entries from the wrong project list during overlapping requests, and its mobile layout may make the entry panel unusable; these current-head correctness and usability risks should be addressed or explicitly accepted before merging.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant ProjectWorkspace
  participant ProjectLists
  participant projectsApi

  User->>ProjectWorkspace: Select Lists tab
  ProjectWorkspace->>ProjectLists: Render project lists
  ProjectLists->>projectsApi: Load lists and entries
  projectsApi-->>ProjectLists: Return list data
  User->>ProjectLists: Add or update an entry
  ProjectLists->>projectsApi: Submit entry mutation
  projectsApi-->>ProjectLists: Return updated data
  ProjectLists->>projectsApi: Refresh entries
Loading

Possibly related PRs

  • jaylfc/taOS#2336 — Introduces the project-lists CRUD API consumed by this PR.
  • jaylfc/taOS#2377 — Introduces the project-list CRUD and reorder routes used by the API client.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the main change: adding a Lists tab to the Projects app.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch exec/tsk-zitqoj

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

.then((ls) => {
if (!cancelled) {
setLists(ls);
if (!selectedListId && ls.length > 0) setSelectedListId(ls[0]!.id);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WARNING: selectedListId is not reset when project.id changes

When the user navigates to a different project, the selectedListId state persists. If the new project has a list with the same ID as the previously selected list, the entries panel will display entries from the wrong list. If no matching list exists, the component shows an error. This state should be reset when the project changes.


Reply with @kilocode-bot fix it to have Kilo Code address this issue.


const createList = async () => {
const title = prompt("New list name");
if (!title) return;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WARNING: createList accepts whitespace-only titles

if (!title) return; does not catch inputs like " ". After title.trim(), the resulting empty string is passed to the API, potentially creating a list with an empty title. Use if (!title.trim()) return; instead.


Reply with @kilocode-bot fix it to have Kilo Code address this issue.

role="button"
aria-label={`View original text for ${entry.text}`}
onKeyDown={(e) => { if (e.key === "Enter" || e.key === " ") { e.preventDefault(); alert(entry.original_text); } }}
onClick={() => alert(entry.original_text)}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SUGGESTION: Replace alert() with a non-blocking UI pattern

alert() blocks the main thread and is an intrusive UX pattern. The title attribute already surfaces original_text on hover; consider a tooltip, popover, or inline expansion instead.


Reply with @kilocode-bot fix it to have Kilo Code address this issue.

@kilo-code-bot

kilo-code-bot Bot commented Aug 12, 2026

Copy link
Copy Markdown

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Files Reviewed (2 files)
  • desktop/src/apps/ProjectsApp/ProjectLists.tsx
  • desktop/src/apps/ProjectsApp/__tests__/ProjectLists.test.tsx
Previous Review Summaries (2 snapshots, latest commit 2bd3d2d)

Current summary above is authoritative. Previous snapshots are kept for context only.

Previous review (commit 2bd3d2d)

Status: 5 Issues Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 3
SUGGESTION 2
Issue Details (click to expand)

WARNING

File Line Issue
desktop/src/apps/ProjectsApp/ProjectLists.tsx 61 selectedListId is not reset when project.id changes
desktop/src/apps/ProjectsApp/ProjectLists.tsx 83 createList accepts whitespace-only titles
desktop/src/apps/ProjectsApp/ProjectLists.tsx 51 refreshEntries can overwrite entries with a stale response

SUGGESTION

File Line Issue
desktop/src/apps/ProjectsApp/ProjectLists.tsx 278 Replace alert() with a non-blocking UI pattern
desktop/src/apps/ProjectsApp/ProjectLists.tsx 153 Stack list panels vertically on mobile screens
Files Reviewed (2 files)
  • desktop/src/apps/ProjectsApp/ProjectLists.tsx - 5 issues
  • desktop/src/apps/ProjectsApp/__tests__/ProjectLists.test.tsx

Fix these issues in Kilo Cloud

Previous review (commit 0b0cf82)

Status: 3 Issues Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 2
SUGGESTION 1
Issue Details (click to expand)

WARNING

File Line Issue
desktop/src/apps/ProjectsApp/ProjectLists.tsx 52 selectedListId not reset when project.id changes
desktop/src/apps/ProjectsApp/ProjectLists.tsx 74 createList accepts whitespace-only titles

SUGGESTION

File Line Issue
desktop/src/apps/ProjectsApp/ProjectLists.tsx 269 Replace alert() with a non-blocking UI pattern
Files Reviewed (5 files)
  • desktop/src/apps/ProjectsApp/ProjectLists.tsx - 3 issues
  • desktop/src/apps/ProjectsApp/ProjectWorkspace.tsx
  • desktop/src/apps/ProjectsApp/ProjectsApp.module.css
  • desktop/src/apps/ProjectsApp/__tests__/ProjectLists.test.tsx
  • desktop/src/lib/projects.ts

Fix these issues in Kilo Cloud


Reviewed by step-3.7-flash · Input: 97K · Output: 19.3K · Cached: 349.4K

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@desktop/src/apps/ProjectsApp/ProjectLists.tsx`:
- Around line 31-42: Update refreshEntries to track the selected-list request
and ignore responses or errors that no longer belong to the current
selectedListId, preventing list A results from replacing list B entries. Ensure
both setEntries and setError are guarded by the active request/list identity
while preserving the existing empty-list behavior.
- Line 144: Update the container div in ProjectLists so its flex direction
changes to a vertical column below the 768px breakpoint, while preserving the
existing horizontal row layout on larger screens. Ensure the listsRail and
entries panel stack with usable width on mobile.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 32450318-f3c4-4f51-8d11-fcb46bdb0d7a

📥 Commits

Reviewing files that changed from the base of the PR and between 7531a5f and 0b0cf82.

📒 Files selected for processing (5)
  • desktop/src/apps/ProjectsApp/ProjectLists.tsx
  • desktop/src/apps/ProjectsApp/ProjectWorkspace.tsx
  • desktop/src/apps/ProjectsApp/ProjectsApp.module.css
  • desktop/src/apps/ProjectsApp/__tests__/ProjectLists.test.tsx
  • desktop/src/lib/projects.ts

Comment thread desktop/src/apps/ProjectsApp/ProjectLists.tsx

return (
<div className="flex flex-col h-full min-h-0">
<div className="flex flex-1 min-h-0 gap-3">

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Stack the list panels on mobile screens.

Below 768px, .listsRail is width: 100% and flex: none, but this container remains a horizontal flex row. The rail consumes the available row width, so the entries panel has no usable width.

Proposed fix
-      <div className="flex flex-1 min-h-0 gap-3">
+      <div className="flex flex-1 min-h-0 flex-col gap-3 md:flex-row">
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<div className="flex flex-1 min-h-0 gap-3">
<div className="flex flex-1 min-h-0 flex-col gap-3 md:flex-row">
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@desktop/src/apps/ProjectsApp/ProjectLists.tsx` at line 144, Update the
container div in ProjectLists so its flex direction changes to a vertical column
below the 768px breakpoint, while preserving the existing horizontal row layout
on larger screens. Ensure the listsRail and entries panel stack with usable
width on mobile.

@jaylfc

jaylfc commented Aug 12, 2026

Copy link
Copy Markdown
Owner Author

nemotron-super review

VERDICT: Blocking issues found.

  • desktop/src/apps/ProjectsApp/ProjectLists.tsx:42
  • desktop/src/apps/ProjectsApp/ProjectLists.tsx:82
  • desktop/src/apps/ProjectsApp/ProjectLists.tsx:104
  • desktop/src/apps/ProjectsApp/ProjectLists.tsx:119
  • desktop/src/apps/ProjectsApp/ProjectLists.tsx:134
  • desktop/src/apps/ProjectsApp/ProjectLists.tsx:149
  • desktop/src/apps/ProjectsApp/ProjectLists.tsx:164
  • desktop/src/apps/ProjectsApp/ProjectLists.tsx:179
  • desktop/src/apps/ProjectsApp/ProjectLists.tsx:194
  • desktop/src/apps/ProjectsApp/ProjectLists.tsx:209
  • desktop/src/apps/ProjectsApp/ProjectLists.tsx:224
  • desktop/src/apps/ProjectsApp/ProjectLists.tsx:239
  • desktop/src/apps/ProjectsApp/ProjectLists.tsx:254
  • desktop/src/apps/ProjectsApp/ProjectLists.tsx:269
  • desktop/src/apps/ProjectsApp/ProjectLists.tsx:284
  • desktop/src/apps/ProjectsApp/ProjectLists.tsx:299
  • desktop/src/apps/ProjectsApp/ProjectLists.tsx:314
  • No blocking issues found.

Automated first-pass review by the nemotron-super lane. The lead still reviews before merge.

refreshLists() fetched the lists and returned them without calling
setLists, and the mount effect was the only caller that stored the
result. createList and deleteList each awaited refreshLists() and
discarded it, so a created list never appeared in the rail and a
deleted one never left it. The entry paths were unaffected because
refreshEntries already set its own state, which is why the existing
tests all passed: they cover entries, not lists.

refreshLists now sets state and returns the lists, matching
refreshEntries.

Two tests added for the paths that had none, both proven to fail
against 0b0cf82 first ("Unable to find an element with the text: New
list"). The fetch mock is now stateful for lists as it already was for
entries, because a fixed lists response cannot tell a refreshed rail
from a stale one.

Docs-Reviewed: no desktop app was added or removed. ProjectLists.tsx is
a component inside the existing Projects app, so README's app list and
count are unchanged. The doc-gate 'apps' rule matches
desktop/src/apps/*/** and so fires on any file added under any existing
app; that rule defect is carded separately and is not fixed here.
@jaylfc

jaylfc commented Aug 12, 2026

Copy link
Copy Markdown
Owner Author

[LEAD REVIEW] Lead-completed rather than bounced: this lane exits after opening its PR, so a demand posted here would reach nobody.

ONE REAL BUG, and the passing tests are why it survived. refreshLists() fetched the lists and RETURNED them without ever calling setLists - the mount effect was the only caller that stored a result. createList and deleteList each await refreshLists() and discard it, so:

  • creating a list left the rail unchanged while selectedListId moved to the new id, so the header fell back to EMPTY_LIST and the user saw a blank "Untitled list" with their new list missing from the rail;
  • deleting a list left it visible in the rail, and clicking it then 404s.
    The entry paths were fine because refreshEntries sets its own state. That asymmetry is the tell, and it is exactly why the five existing tests passed: every one of them exercises entries, none touches a list.

Fixed in 2bd3d2d by making refreshLists set state and return, matching refreshEntries.

RED FIRST, against this PR's own head 0b0cf82, with the final test file:

 FAIL  src/apps/ProjectsApp/__tests__/ProjectLists.test.tsx > ProjectLists > a created list appears in the rail
TestingLibraryElementError: Unable to find an element with the text: New list.
 FAIL  src/apps/ProjectsApp/__tests__/ProjectLists.test.tsx > ProjectLists > a deleted list disappears from the rail
      Tests  2 failed | 5 passed (7)

and with the fix in place:

 Test Files  1 passed (1)
      Tests  7 passed (7)

tsc --noEmit rc 0.

The fetch mock is now STATEFUL for lists, as it already was for entries. It returned a fixed one-list array for every GET, which means it could not have distinguished a refreshed rail from a stale one no matter what was asserted. A mock that ignores writes cannot test a refresh.

TWO THINGS I DID NOT CHANGE, deliberately:

  1. projectsApi.lists.list does .then((r) => r.items) with no fallback, so a 200 whose body lacks items renders undefined and crashes on entries.length. I hit this while writing the tests. I did NOT add ?? []: that is precisely the anti-pattern caught on the LoRA Studio review three hours ago, where listLoras swallowed a 500 into an empty list and showed "No LoRAs yet" over a server error. The routes always send items; if that ever stops being true the crash is the honest signal.
  2. prompt() and confirm() for list create/delete are browser-native dialogs in an OS shell that has its own chrome. Not blocking this PR, but it does not meet the UI bar and should become real dialogs.

DOC-GATE: the changelog half was a real miss and is now fixed with a fragment. The apps half is a FALSE POSITIVE in my own gate: the rule globs desktop/src/apps/*/**, so it fires on any file added inside an app that already exists, while its hint says "a desktop app was added or removed". Cleared with a Docs-Reviewed trailer explaining exactly that, and the rule defect is carded as tsk-2co4om with a demand to prove both directions (a nested file must stop failing; a genuinely new app must still fail without a README edit).

Gate on green: gate_merge.sh 2379 tsk-zitqoj.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@desktop/src/apps/ProjectsApp/__tests__/ProjectLists.test.tsx`:
- Around line 43-48: Update the creation test around the POST mock and its “New
list” assertion to scope the lookup to the rail container, then assert the
created list item within that container. Use the rail’s existing accessible role
or test identifier rather than searching the whole document, so the assertion
verifies refreshLists() updates the rail state.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 0eaf17ef-e38b-44e8-95de-ea2692df4631

📥 Commits

Reviewing files that changed from the base of the PR and between 0b0cf82 and 2bd3d2d.

📒 Files selected for processing (3)
  • changelog.d/2379-projects-lists-tab.md
  • desktop/src/apps/ProjectsApp/ProjectLists.tsx
  • desktop/src/apps/ProjectsApp/__tests__/ProjectLists.test.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • desktop/src/apps/ProjectsApp/ProjectLists.tsx

Comment thread desktop/src/apps/ProjectsApp/__tests__/ProjectLists.test.tsx
jaylfc added 2 commits August 12, 2026 23:51
Two review findings, both reachable and both proven red first.

ProjectWorkspace renders <ProjectLists project={project} /> with no
key and is itself rendered unkeyed, so switching project reuses this
component instead of remounting it. selectedListId survived the switch
and the entries effect then fetched
/api/projects/<new>/lists/<old-list-id>/entries, showing the previous
project's entries against the new project.

Resetting in an effect is not enough: the entries effect re-runs in the
same commit because its deps include project.id, so it fires with the
stale id before any effect-based reset lands. The selection is now
dropped during render (React's adjust-state-on-prop-change pattern),
which runs before effects. The lists effect additionally keeps a
selection only if it belongs to the lists just fetched.

createList trimmed the title only after the empty check, so a
whitespace-only answer to the prompt reached the API as an empty title.

Docs-Reviewed: no user-visible behaviour beyond the Lists tab already
described in changelog.d/2379-projects-lists-tab.md, and no desktop app
was added or removed.
Both bots flagged this independently. refreshEntries wrote whatever
came back, so two quick list clicks raced and the slower response
landed last, showing one list's entries under another's heading. The
response is now dropped unless its list is still the selected one,
compared against a ref because the closure's own copy is stale by
definition.

Covered by a deterministic race test: lst-1's fetch is held open, the
user selects lst-2, then lst-1's response is released. It fails without
the guard with "STALE MILK" on screen.

The created-list assertion is now scoped to the rail. It searched the
whole document, and the entries header renders the selected list's
title too, so it could have passed while the rail stayed stale.

Docs-Reviewed: behaviour is already covered by
changelog.d/2379-projects-lists-tab.md and no desktop app was added or
removed.
@jaylfc

jaylfc commented Aug 12, 2026

Copy link
Copy Markdown
Owner Author

[LEAD] Bot round adjudicated at head 95465c0. Kilo re-reviewed at 2bd3d2d (5 issues, its own summary marks that one authoritative and keeps the 0b0cf82 one for context); CodeRabbit posted at 2bd3d2d. THREE ACCEPTED, TWO DEFERRED WITH A CARD, ONE BOT OUTPUT REJECTED AS UNUSABLE.

ACCEPTED 1 - kilo WARNING, selectedListId not reset when project.id changes. REAL and reachable: ProjectWorkspace renders <ProjectLists project={project} /> with no key, and index.tsx renders <ProjectWorkspace project={selected} /> unkeyed too, so a project switch reuses the component. I verified both call sites rather than assuming a remount.
My first attempt at this was WRONG and the test caught it: resetting inside the lists effect still let the entries effect fire first in the same commit (its deps include project.id), so the stale fetch /api/projects/p2/lists/lst-1/entries still went out and crashed the render on an unmatched shape. Fixed properly by dropping the selection DURING RENDER (React's adjust-state-on-prop-change pattern), which runs before any effect.

ACCEPTED 2 - kilo WARNING, whitespace-only titles. if (!title) return; does not catch " ", and the trim happened after. One-line fix, test asserts no POST is made.

ACCEPTED 3 - kilo WARNING and CodeRabbit Major, both independently: stale entries response. refreshEntries wrote whatever came back, so two quick clicks race and the slower response lands last under the wrong heading. Guarded against a ref holding the current selection. Covered by a deterministic race test (lst-1's fetch held open, select lst-2, then release) which fails without the guard with "STALE MILK" on screen.

ACCEPTED 4 - CodeRabbit Minor, on MY test: getAllByText("New list") searched the whole document while the entries header also renders the selected list's title, so it could have passed while the rail stayed stale. Now scoped to the rail with within. Correct catch on a wrong-reason green.

DEFERRED, carded not skipped - mobile stacking (CodeRabbit Major, kilo SUGGESTION): below 768px .listsRail is width:100% but the container stays a horizontal flex row, so the panels do not stack. Real, and this app already has a mobile surface, but it is a layout change that needs to be looked at rather than asserted, and I cannot screenshot it in this pass. Not folded in silently.

DEFERRED - alert() for the original text (kilo SUGGESTION), plus prompt()/confirm() for list create and delete, which no bot raised. Browser-native dialogs in an OS shell that has its own chrome. Same card.

REJECTED AS UNUSABLE - the nemotron-super lane's comment. It says "VERDICT: Blocking issues found", lists seventeen line numbers at a fixed 15-line stride (82, 104, 119, 134 ... 314), and then ends with "No blocking issues found". A verdict contradicted by its own list, with line numbers that are an arithmetic sequence rather than findings, is not a review artifact. Recorded against that lane's known over-reporting; nothing in it was actionable.

Red evidence for this round, all against this PR's own earlier heads with the final tests:

 FAIL > switching project does not keep the previous project's selected list
TypeError: Cannot read properties of undefined (reading 'length')
 FAIL > a whitespace-only list name creates nothing
AssertionError: expected [ '/api/projects/p1/lists', ...(1) ] to be undefined
      Tests  2 failed | 7 passed (9)
 FAIL > a slow entries response for a deselected list does not overwrite the current one
  STALE MILK
      Tests  1 failed | 9 passed (10)

Green now: 10/10, tsc --noEmit rc 0.

@jaylfc

jaylfc commented Aug 12, 2026

Copy link
Copy Markdown
Owner Author

[LEAD] The two deferred UI items are carded as tsk-7wwcdg (mobile stacking + replacing prompt/confirm/alert with the app's own dialogs), with a grep-based acceptance check and red-first demanded. Carded before citing the id, so this is the real one.

@jaylfc

jaylfc commented Aug 13, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai full review

Requesting a fresh artifact rather than reusing the round at 2bd3d2d: two commits since then changed PRODUCTION code, not just tests. f8cf50e drops the previous project's selection during render (the effect-based reset fired too late, so the stale entries fetch still went out) and trims the list title before the empty check; 95465c0 ignores an entries response whose list is no longer selected, covered by a deterministic race test that fails without the guard. Current head is 95465c0.

@coderabbitai

coderabbitai Bot commented Aug 13, 2026

Copy link
Copy Markdown

@jaylfc A fresh full review will evaluate the current head 95465c05, including the project-switch selection reset, trimmed list-title validation, and stale-entry response guard.

⚠️ Action not completed

Review rate limited.


Your included review limit is currently reached under our Fair Usage Limits Policy. This review may still proceed through usage-based billing if eligible. Your next included review will be available in 57 seconds.

@jaylfc

jaylfc commented Aug 13, 2026

Copy link
Copy Markdown
Owner Author

[LEAD] Merging on the documented rate-limit fallback, stated plainly rather than dressed up as a clean bot round.

BOT POSTURE, honestly: the newest CodeRabbit artifact is for 2bd3d2d and kilo's newest is also 2bd3d2d. Current head is 95465c0. I requested a fresh full review, CodeRabbit acknowledged it would evaluate 95465c0, and no artifact arrived within an 11 minute wait. Kilo's check reads SUCCESS with an EMPTY description, which is the run completing, not a review artifact for this head. So neither bot has reviewed the last two commits and I am not going to pretend otherwise.

WHAT IS ACTUALLY UNREVIEWED BY A BOT, and why I judge it safe to merge:

  • f8cf50e: drop the previous project's selection during render, and trim the list title before the empty check. Both were kilo's OWN findings from the 2bd3d2d round, so the bot has seen the problem; what it has not seen is my fix. Both covered by tests proven red first.
  • 95465c0: ignore an entries response whose list is no longer selected. This was kilo's W3 AND CodeRabbit's Major on the same round, again a finding both bots raised. Covered by a deterministic race test that fails without the guard with "STALE MILK" on screen.
    Every change since the last artifact is a fix to something a bot asked for, each with a red-proven test, none introducing a new surface. CI is fully green at 95465c0 (0 failing, 0 pending) and I reviewed the diff line by line myself, which is how the refreshLists bug was found in the first place: no bot flagged it.

Two deferred items are carded as tsk-7wwcdg (mobile stacking, native prompt/confirm/alert). The nemotron-super comment on this PR was rejected as structurally malformed, with evidence recorded on tsk-x6fzgf.

@jaylfc
jaylfc merged commit 8497001 into dev Aug 13, 2026
21 checks passed
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.

1 participant