Skip to content

feat(coordination): unified worklist screen (Variant C)#173

Merged
TraderSamwise merged 4 commits into
masterfrom
chore/tui-next-28
Jun 19, 2026
Merged

feat(coordination): unified worklist screen (Variant C)#173
TraderSamwise merged 4 commits into
masterfrom
chore/tui-next-28

Conversation

@TraderSamwise

@TraderSamwise TraderSamwise commented Jun 19, 2026

Copy link
Copy Markdown
Owner

Summary

Replaces the two-section Inbox/Threads Coordination screen with one agent-keyed, urgency-sorted worklist (the "Variant C" mockup), now that the information layer is reconciled. Presentation + interaction restructure; the data model was already reconciled in #171/#172.

  • Unified model (3b1862d): new pure buildCoordinationWorklist merges the reconciled notification model and genuine (non-notification) threads into one stream. Each row carries a type (msg/note/task/review/handoff/conversation) and a bucket (needs-you/handled/unreachable) on a unified urgency scale, so notifications and threads interleave sensibly (live needs-input > on-you thread > pending thread > offline unread > handled > stale > missing). Threads are first-class rows (each appears once).
  • Screen cutover (7a12809): one selection index; Tab is now a filter (all / threads) rather than a section switch; per-row actions dispatch by item kind — notifications keep r/c/Enter (+ global R/C), threads keep s/A/c/b/o/x/P/J/E/Enter. refreshNotificationEntries builds the worklist so every mutation site stays coherent; the reply overlay's threadIndex is synced from the selected thread. Direct cutover — the Inbox/Threads split is gone.
  • Polish (a7b5dbf): footer reflects the selected row's verbs; bucket boundaries are dashboard-style titled rules (Needs you ── N, accent); the detail pane is rounded card()s (Inbox/Thread + Body/Messages).

Test plan

  • yarn typecheck, yarn lint, full yarn vitest (1465 passing), yarn build — all clean.
  • Each phase passed an independent plan-audit + implementation-audit (Explore agents) before commit.
  • Rebuilt + installed local 0.1.21-tui-ia for live verification.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Unified coordination view merging notifications and threads into a single sorted list by urgency.
    • Added filtering to view threads only or all items combined.
    • Simplified navigation with a single index for both notifications and threads.
  • Bug Fixes

    • Improved deduplication ensuring threads display once despite related notifications.

test and others added 3 commits June 19, 2026 12:09
Add pure buildCoordinationWorklist: merges the reconciled notification model and
the genuine (non-notification) threads into one agent-keyed, urgency-sorted
stream. Each row carries a type (msg/note/task/review/handoff/conversation) and a
bucket (needs-you/handled/unreachable) on a unified urgency scale so notifications
and threads interleave sensibly (live needs-input > on-you thread > pending thread
> offline unread > handled > stale > missing). Threads are first-class rows (the
model's per-item thread annotation is ignored) so each appears exactly once.
Dormant until the view is cut over.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace the two-section Inbox/Threads Coordination screen with one
agent-keyed, urgency-sorted worklist driven by buildCoordinationWorklist.
Single selection index (coordinationIndex); Tab is now a filter (all/threads)
rather than a section switch; per-row actions dispatch by item kind —
notifications keep r/c/Enter (+ global R/C), threads keep s/A/c/b/o/x/P/J/E/Enter.
refreshNotificationEntries now also builds threadEntries + the worklist so every
mutation site keeps the screen coherent. Rows show a type chip
(msg/note/task/review/handoff/conversation), reachability/stale tags, and bucket
rules (Needs you / Handled / Unreachable); the detail pane dispatches by kind.
openSelectedNotification → openCoordinationNotification (agent rollup). The
reply overlay still reads threadEntries[threadIndex], synced from the selected
worklist thread on reply.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Polish the unified worklist to match the Variant C mockup. The footer now
reflects the selected row's actions (notification verbs vs thread verbs). Bucket
boundaries render as dashboard-style titled rules ("Needs you ── N", accent for
the actionable bucket) instead of muted dividers. The detail pane is wrapped in
rounded card()s (Inbox/Thread + Body/Messages), matching the Dashboard. Pure
presentation; no model/handler changes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@vercel

vercel Bot commented Jun 19, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
app Ready Ready Preview, Comment Jun 19, 2026 5:02am

@coderabbitai

coderabbitai Bot commented Jun 19, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@TraderSamwise, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 2 hours, 33 minutes, and 58 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

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 credits.

🚦 How do rate limits work?

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

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, the refill rate gradually slows as usage increases. The highest same-day bursts are limited more strictly.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 19eea5fa-5af8-49e5-80c2-dacdfedd4f01

📥 Commits

Reviewing files that changed from the base of the PR and between a7b5dbf and cc672ab.

📒 Files selected for processing (3)
  • src/coordination-model.ts
  • src/multiplexer/coordination.ts
  • src/multiplexer/notifications.ts
📝 Walkthrough

Walkthrough

Adds a buildCoordinationWorklist function and associated types to coordination-model.ts that merges notification-derived and thread-derived rows into a single urgency-sorted stream. The multiplexer replaces its coordinationSection toggle with coordinationWorklist, coordinationIndex, and coordinationFilter fields, and all coordination UI paths—notification refresh, open/read, key dispatch, subscreen navigation, and TUI rendering—are updated to use this unified index.

Changes

Unified Coordination Worklist

Layer / File(s) Summary
Worklist types, helpers, and buildCoordinationWorklist
src/coordination-model.ts, src/coordination-model.test.ts
Exports WorklistType, WorklistBucket, WorklistItem, and CoordinationWorklist types; adds local urgency-scoring and kind-mapping helpers; implements buildCoordinationWorklist merging n:-prefixed notification rows and t:-prefixed thread rows into a unified urgency+recency sorted array with needsYou/tail partitions. Tests cover interleaved ordering, row classification, and deduplication.
Multiplexer class: worklist state fields
src/multiplexer/index.ts
Replaces the coordinationSection private field with coordinationWorklist: WorklistItem[], coordinationIndex: number, and coordinationFilter: "all" | "threads" on the Multiplexer class; adds WorklistItem to the coordination-model import.
Notification refresh, open, and state init
src/multiplexer/notifications.ts, src/multiplexer/notifications.test.ts
refreshNotificationEntries rebuilds thread entries, constructs full model input, stores coordinationModel, derives coordinationWorklist, applies optional threads-only filter, and clamps coordinationIndex. ensureNotificationState initializes the new fields. openSelectedNotification is replaced by openCoordinationNotification(host, item) with markCoordinationItemRead for session-based and sessionless items plus settle-after-open logic. Tests update fixtures to use the new fields and add a full navigate/filter/read integration test.
Coordination show, render, and key dispatch
src/multiplexer/coordination.ts
Adds clampCoordinationIndex; showCoordination and renderCoordination clamp the index; Tab flips coordinationFilter between "threads" and "all" and resets index; arrow/numeric keys update coordinationIndex within coordinationWorklist; item dispatch branches on item.kind instead of section.
openRelevantThreadForSession aligned to worklist
src/multiplexer/subscreens.ts, src/multiplexer/subscreens.test.ts
After selecting a target thread, sets coordinationFilter to "all", calls refreshNotificationEntries, and searches coordinationWorklist for the matching thread id to set coordinationIndex. Tests update host stubs to use coordinationWorklist and coordinationIndex.
TUI coordination screen and details pane
src/tui/screens/subscreen-renderers.ts
Adds WORKLIST_TYPE_TONE, WORKLIST_BUCKET_LABEL, worklistTags, bucketRule, and coordinationFooterHints helpers; rewrites renderCoordinationScreen to drive from ctx.coordinationWorklist with bucket grouping and selection focus; rewrites renderCoordinationDetails to dispatch by item.kind with a paired card layout using a new padDetail helper.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant CoordinationKeyHandler
  participant refreshNotificationEntries
  participant buildCoordinationWorklist
  participant openCoordinationNotification
  participant renderCoordinationScreen

  User->>CoordinationKeyHandler: open coordination screen
  CoordinationKeyHandler->>refreshNotificationEntries: rebuild entries
  refreshNotificationEntries->>buildCoordinationWorklist: modelInput + threads
  buildCoordinationWorklist-->>refreshNotificationEntries: merged WorklistItem[]
  refreshNotificationEntries-->>CoordinationKeyHandler: host.coordinationWorklist set
  CoordinationKeyHandler->>renderCoordinationScreen: draw with coordinationWorklist + coordinationIndex

  User->>CoordinationKeyHandler: press Tab
  CoordinationKeyHandler-->>CoordinationKeyHandler: flip coordinationFilter, reset coordinationIndex=0
  CoordinationKeyHandler->>renderCoordinationScreen: redraw filtered view

  User->>CoordinationKeyHandler: press Enter on selected item
  CoordinationKeyHandler->>openCoordinationNotification: host + WorklistItem
  openCoordinationNotification-->>CoordinationKeyHandler: activate session/service, mark read, settle
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • TraderSamwise/aimux#157: Modifies the same coordination.ts and notifications.ts files to build out the merged Coordination screen; this PR replaces that section-based handler split with the unified worklist index model.
  • TraderSamwise/aimux#171: Establishes buildCoordinationModel and its reachability/actionable/stale classification that buildCoordinationWorklist directly consumes to derive notification worklist rows.

Poem

🐇 Hop, hop! Two lists became one,
A worklist merged under a single sun.
Notifications and threads in a unified stream,
Urgency-sorted—a reviewer's dream!
One index to rule them, one filter to flip,
The rabbit approves this most elegant trip. ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 23.53% 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 summarizes the main change: introducing a unified worklist screen for coordination, which is the primary architectural refactor described throughout the PR.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch chore/tui-next-28

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

@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

🧹 Nitpick comments (4)
src/multiplexer/notifications.ts (1)

191-197: ⚡ Quick win

Duplicate of readNotificationItem in coordination.ts.

This function is identical to readNotificationItem at src/multiplexer/coordination.ts:55-60 (see context snippet 1). Consider exporting one version and reusing it to avoid divergence.

🤖 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 `@src/multiplexer/notifications.ts` around lines 191 - 197, The function
markCoordinationItemRead in notifications.ts is a duplicate of
readNotificationItem from coordination.ts that performs identical logic. Remove
the markCoordinationItemRead function definition and instead import
readNotificationItem from coordination.ts, then update all call sites in
notifications.ts to use the imported readNotificationItem function instead of
the local markCoordinationItemRead function.
src/coordination-model.ts (2)

281-286: ⚡ Quick win

Duplicate model construction on every refresh.

buildCoordinationWorklist internally calls buildCoordinationModel(input) on line 285. However, in refreshNotificationEntries (src/multiplexer/notifications.ts:101), the caller already builds the model for host.coordinationModel. This results in the same model being constructed twice per refresh cycle.

Consider accepting the pre-built model as an optional parameter or refactoring to avoid the redundant computation.

♻️ Suggested refactor
 export function buildCoordinationWorklist(
-  input: BuildCoordinationModelInput & { currentParticipant?: string },
+  input: BuildCoordinationModelInput & { currentParticipant?: string; model?: CoordinationModel },
 ): CoordinationWorklist {
   const participant = input.currentParticipant ?? "user";
-  const model = buildCoordinationModel(input);
+  const model = input.model ?? buildCoordinationModel(input);
   const items: WorklistItem[] = [];

Then in refreshNotificationEntries:

   const model = buildCoordinationModel(modelInput);
   host.coordinationModel = model;
   // ...
-  const worklist = buildCoordinationWorklist(modelInput);
+  const worklist = buildCoordinationWorklist({ ...modelInput, model });
🤖 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 `@src/coordination-model.ts` around lines 281 - 286, The
buildCoordinationWorklist function unnecessarily calls buildCoordinationModel
internally on every invocation, even though refreshNotificationEntries in
notifications.ts already builds this model separately and passes it to
host.coordinationModel, causing duplicate model construction per refresh cycle.
Refactor buildCoordinationWorklist to accept the pre-built coordination model as
an optional parameter (e.g., coordinationModel?: CoordinationModel) in the input
object, and use that provided model instead of calling buildCoordinationModel
internally. Update the caller in refreshNotificationEntries to pass the
already-constructed model to avoid redundant computation.

260-263: 💤 Low value

Stale notifications may be incorrectly bucketed as "unreachable".

The notificationBucket function places stale items in the "unreachable" bucket alongside missing-target items. However, stale notifications are still reachable (the agent exists and is live); they're just likely outdated. This conflates two different semantic states in the UI grouping.

Consider whether stale items should fall into "handled" instead, or introduce a separate bucket for display differentiation.

🤖 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 `@src/coordination-model.ts` around lines 260 - 263, The notificationBucket
function incorrectly groups stale items with missing-target items in the
"unreachable" bucket, but stale notifications are still reachable and should be
treated differently to reflect their distinct semantic state. Modify the
conditional logic in notificationBucket to separate the handling of missing
items (where reachability === "missing") from stale items, so that only truly
unreachable items return "unreachable" and stale items are instead placed in the
"handled" bucket or a new separate bucket for stale notifications depending on
the desired UI behavior.
src/multiplexer/subscreens.test.ts (1)

78-79: 💤 Low value

Missing key field in test mock for consistency.

Line 40's worklist item includes key: "t:thread-1", but this mock is missing the key field. While the current code doesn't appear to rely on key during dispatch, adding it maintains consistency with the WorklistItem contract and protects against future changes that might use it.

Suggested fix
-      coordinationWorklist: [{ kind: "thread", thread: buildThreadEntries()[0] }],
+      coordinationWorklist: [{ kind: "thread", key: "t:test-thread", thread: buildThreadEntries()[0] }],
🤖 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 `@src/multiplexer/subscreens.test.ts` around lines 78 - 79, The worklist item
in the coordinationWorklist array is missing the key field that exists in the
similar mock at line 40. Add the key field to the worklist item object (the one
with kind "thread" and thread property) to match the WorklistItem contract
structure, using a consistent format similar to what appears on line 40 (e.g.,
key: "t:thread-1" or an appropriate identifier based on the buildThreadEntries()
result).
🤖 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 `@src/multiplexer/notifications.ts`:
- Around line 116-118: The `refreshNotificationEntries` function clamps
`coordinationIndex` to 0 when the worklist is empty using Math.max(0,
host.coordinationWorklist.length - 1), but the `ensureNotificationState`
function at line 144 initializes `coordinationIndex` to -1 when the list is
empty. Fix this inconsistency by updating `ensureNotificationState` to
initialize `coordinationIndex` to 0 instead of -1 when the coordination worklist
is empty, ensuring both functions use the same convention for empty-list
handling.

---

Nitpick comments:
In `@src/coordination-model.ts`:
- Around line 281-286: The buildCoordinationWorklist function unnecessarily
calls buildCoordinationModel internally on every invocation, even though
refreshNotificationEntries in notifications.ts already builds this model
separately and passes it to host.coordinationModel, causing duplicate model
construction per refresh cycle. Refactor buildCoordinationWorklist to accept the
pre-built coordination model as an optional parameter (e.g., coordinationModel?:
CoordinationModel) in the input object, and use that provided model instead of
calling buildCoordinationModel internally. Update the caller in
refreshNotificationEntries to pass the already-constructed model to avoid
redundant computation.
- Around line 260-263: The notificationBucket function incorrectly groups stale
items with missing-target items in the "unreachable" bucket, but stale
notifications are still reachable and should be treated differently to reflect
their distinct semantic state. Modify the conditional logic in
notificationBucket to separate the handling of missing items (where reachability
=== "missing") from stale items, so that only truly unreachable items return
"unreachable" and stale items are instead placed in the "handled" bucket or a
new separate bucket for stale notifications depending on the desired UI
behavior.

In `@src/multiplexer/notifications.ts`:
- Around line 191-197: The function markCoordinationItemRead in notifications.ts
is a duplicate of readNotificationItem from coordination.ts that performs
identical logic. Remove the markCoordinationItemRead function definition and
instead import readNotificationItem from coordination.ts, then update all call
sites in notifications.ts to use the imported readNotificationItem function
instead of the local markCoordinationItemRead function.

In `@src/multiplexer/subscreens.test.ts`:
- Around line 78-79: The worklist item in the coordinationWorklist array is
missing the key field that exists in the similar mock at line 40. Add the key
field to the worklist item object (the one with kind "thread" and thread
property) to match the WorklistItem contract structure, using a consistent
format similar to what appears on line 40 (e.g., key: "t:thread-1" or an
appropriate identifier based on the buildThreadEntries() result).
🪄 Autofix (Beta)

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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 98e021ca-08b4-474b-b205-7636a2379fb1

📥 Commits

Reviewing files that changed from the base of the PR and between 9ab4147 and a7b5dbf.

📒 Files selected for processing (9)
  • src/coordination-model.test.ts
  • src/coordination-model.ts
  • src/multiplexer/coordination.ts
  • src/multiplexer/index.ts
  • src/multiplexer/notifications.test.ts
  • src/multiplexer/notifications.ts
  • src/multiplexer/subscreens.test.ts
  • src/multiplexer/subscreens.ts
  • src/tui/screens/subscreen-renderers.ts

Comment thread src/multiplexer/notifications.ts Outdated
… build

Review fixes:
- A stale notice belongs to a LIVE agent that moved on, so bucket it as "handled",
  not "unreachable" (which is for vanished targets).
- buildCoordinationWorklist accepts a prebuilt model; refreshNotificationEntries
  passes the one it already built, so the model is built once per refresh, not twice.
- Drop the byte-for-byte duplicates in coordination.ts (readNotificationItem,
  findCoordinationTarget) and reuse the exported markCoordinationItemRead /
  findNotificationSessionTarget from notifications.ts.
- Empty worklist clamps coordinationIndex to -1 (matching ensureNotificationState's
  no-selection sentinel) instead of 0.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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