fix(ui): hide agent-created tasks by default (#16157)

Hide agent-created, system-created, and chat-channel tasks from independent collections by default. Preserve task hierarchy context and existing inbox participation. Add a saved opt-in checkbox without helper text.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
DottaandPaperclip authored and GitHub committed 2026-10-13 09:26:37 -05:00
1 parent 3f7b00a8d0
commit be380ba155
38 files changed
+1012 -308

No files matched your search

+20
View File
@@ -72,6 +72,26 @@ the latest agent that assigned it to them. If no assignment is available, it use
the latest other commenter, or leaves the recipient empty. A manual recipient
choice stays selected while task data refreshes.
### Task collection creation filters
Tasks and project lists hide agent-created and system-created tasks by default.
The Filters menu's **show agent-created tasks** checkbox includes routine runs,
recovery/watchdog tasks, chat-channel tasks, and other automation. Channel tasks
remain bot-created for this filter even when a human starts the conversation. The choice is saved per company
and collection; Clear filters restores the hidden default. Nested lists preserve
ancestors and expandable subtasks as context without promoting unrelated automated
work to independent results. Agent profiles, routine histories, and task-detail
subtasks retain their full history.
Inbox membership continues to follow human creation, assignment, comments, and
existing qualifying participation actions, including manually running a routine.
Routine ownership or responsibility alone does not subscribe a person to scheduled
runs; opening or reading a task is not participation. Inbox discovery searches and
Blocked hide unrelated automated tasks unless the checkbox is checked, while
preserving tasks admitted by the existing participation rules. Checking it does
not subscribe the user to all automation. Approvals and other non-task items keep
their existing rules.
### Company Skills and Policy
Company skills are shared operating capabilities, not privileged objects by default. Every authenticated agent in a company can create, import, install, edit, update, test, reset, and remove that company's skills unless the company has configured an explicit restriction.
+20
View File
@@ -2187,3 +2187,23 @@ See [the layer architecture](plans/2026-10-09-task-workspaces.md) for resolution
## Company fast-response service
Companies may configure an optional shared API connection and model for short acknowledgements of accepted human turns. Fast responses use direct SDK inference alongside normal agent work, with a three-second admission deadline, bounded prompts/output, current authorization and independent `fast_response` accounting. They are server-marked platform receipts attributed to the agent, never completion, interaction or recovery evidence. Company-sponsored unlinked external senders are explicit; linked-user permission denials are never bypassed. See [fast-responses.md](fast-responses.md) for provider, delivery, history and endpoint contracts.
### Task collection creation visibility (2026-10-13)
Tasks and project collections default to hiding agent/system-created tasks and
provide a saved **show agent-created tasks** filter. Classify creation using
creator identity and origin; assignee/responsible users do not imply human
authorship. Routine executions remain automated even when manually triggered.
Creator-less ordinary tasks are system-created. All chat-channel tasks count as
bot-created for this filter, including human-initiated inbound conversations.
Human ordinary and onboarding tasks remain visible. Apply collection creation filters before search limits and
pagination, and retrieve hierarchy context separately under existing access checks.
Context does not count as independent results or board cards. Bounded context
reads retain loaded rows while users reveal more of the tree.
Inbox membership, archives, unread state, and badges retain existing participation
rules, including assignment, comments, and manual routine runs. Responsibility and
read-only activity do not admit scheduled work. Inbox discovery/Blocked preserve
participated automation and hide unrelated automation by default. Agent profile
history, routine history, and task-detail subtasks remain complete. API consumers
that omit the optional creation filter retain their existing list behavior.
+8
View File
@@ -11,6 +11,14 @@ for format, permission checks, evidence and maintenance.
## `views`
The issue-list API accepts optional `includeAgentCreatedTasks`; false restricts
independent results to human creation before search/pagination. Omission retains
existing agent/API behavior. `includeParticipatedTasks=true` requires a board user
and retains only that authenticated user's existing participation as a creation
visibility exception. Company/private-task access checks still apply. Collection
preferences and hierarchy presentation are browser state, not additional authority.
Source-reviewed behavior; live agent access verification remains separate.
Review: `baseline`.
API: `present` — representative operation IDs:
+11
View File
@@ -37,6 +37,17 @@ narrower/different APIs.
## `organize`
The issue-list API accepts optional `includeAgentCreatedTasks`; false restricts
independent results to human creation before search/pagination. Omission retains
existing agent/API behavior. `includeParticipatedTasks=true` requires a board user
and retains only that authenticated user's existing participation as a creation
visibility exception. Company/private-task access checks still apply. Collection
preferences and hierarchy presentation are browser state, not additional authority.
Source-reviewed behavior; live agent access verification remains separate.
All `chat_channel` origins count as bot-created for creation visibility, including
human-initiated conversations. Existing inbox participation remains independent.
Review: `baseline`.
API: `present` — representative operation IDs:
+2
View File
@@ -46,6 +46,8 @@ cover exclusion of historical automatic read cleanup from user participation,
unread counts, and activity timestamps while retaining explicit user decisions
and audit history.
Manual: Seed a scheduled routine execution owned by the current human. It stays out of Mine until an existing participation rule admits it. Verify comments, assignment, and manual routine runs admit automated tasks while reading alone does not. Inbox discovery and Blocked hide unrelated automation by default; the **show agent-created tasks** checkbox reveals it without subscribing the user. Reload and verify membership, unread badges, archive/resurfacing, and preference persistence.
Manual: Read an unread task, return to Unread, archive a handled item, and reload. Verify personal triage state changes while task status stays correct. Switch users and companies to check isolation.
Seed a completed task whose only activity under the viewing user is automatic
+2
View File
@@ -49,6 +49,8 @@ Use a human/unassigned task to verify persistence without invoking a model.
Automated: [task-list helpers](../../ui/src/pages/Issues.test.tsx) cover search URLs, pagination, deduplication, and presentation constants. The suite does not render the page or exercise filtering, grouping, opening a task, and returning; those interactions still need a running-browser check.
Manual: Seed human-created, agent-created, scheduled routine, human-initiated chat-channel, and creator-less tasks. Confirm automation is hidden by default, **show agent-created tasks** reveals it, reload preserves the choice, and Clear filters hides it again. Verify list and board search with automation newer than the human results, and expand contextual ancestors/subtasks without promoting unrelated automated roots. Repeat in project task lists. Agent profiles and task-detail subtasks retain complete history.
Manual: Filter by status and assignee, change grouping/sort, open a task, and return. Verify the correct records and selected view survive navigation and reload. Include an empty result and a failed request.
### `task-detail`
+51 -50
View File
@@ -4,7 +4,7 @@
[Contract and maintenance](README.md) · [Review findings](REVIEW.md)
223 story files; 2212 indexed stories. Counts describe inventory, not passed tests or complete feature coverage.
223 story files; 2215 indexed stories. Counts describe inventory, not passed tests or complete feature coverage.
Status describes product alignment; implementation describes the rendered subject; boundary describes simulated data. Sources and limitations are in catalog.json. Related capabilities cross-list one canonical story file.
@@ -30,14 +30,14 @@ Sessions, bootstrap, membership, roles, and CLI authorization.
| Story suite | Capabilities | Product / implementation / data | Stories / play functions | Review note |
| --- | --- | --- | --- | --- |
| [Getting started and access/Login, invitations, and access/Private tasks/00 Review guide](../../ui/storybook/stories/access/private-tasks/00-review-guide.stories.tsx) | `access/resources`, `tasks/properties` | unreviewed / guide / static | 1 / 0 | Review guide retained; explanatory content does not establish runtime or production coverage. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. |
| [Getting started and access/Login, invitations, and access/Private tasks/01 Creation](../../ui/storybook/stories/access/private-tasks/01-creation.stories.tsx) | `access/resources`, `tasks/properties` | unreviewed / production / fixtures | 22 / 14 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Master reconciliation inspected assignment-history recipient suggestions and manual-selection retention; existing stories do not establish the new assignment-history behavior. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. |
| [Getting started and access/Login, invitations, and access/Private tasks/02 Sharing](../../ui/storybook/stories/access/private-tasks/02-sharing.stories.tsx) | `access/resources`, `tasks/properties` | unreviewed / production / fixtures | 26 / 10 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. |
| [Getting started and access/Login, invitations, and access/Private tasks/03 Task actions](../../ui/storybook/stories/access/private-tasks/03-task-actions.stories.tsx) | `access/resources`, `tasks/properties` | unreviewed / production / fixtures | 11 / 7 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. |
| [Getting started and access/Login, invitations, and access/Private tasks/04 References and blockers](../../ui/storybook/stories/access/private-tasks/04-references-and-blockers.stories.tsx) | `access/resources`, `tasks/properties` | unreviewed / production / fixtures | 12 / 5 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. |
| [Getting started and access/Login, invitations, and access/Private tasks/05 Projects](../../ui/storybook/stories/access/private-tasks/05-projects.stories.tsx) | `access/resources`, `tasks/properties`, `projects/lifecycle` | unreviewed / production / fixtures | 19 / 12 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. |
| [Getting started and access/Login, invitations, and access/Private tasks/06 Full product pages](../../ui/storybook/stories/access/private-tasks/06-full-product-pages.stories.tsx) | `access/resources`, `tasks/properties`, `projects/lifecycle` | unreviewed / production / fixtures | 21 / 12 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Master reconciliation inspected assignment-history recipient suggestions and manual-selection retention; existing stories do not establish the new assignment-history behavior. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. |
| [Getting started and access/Login, invitations, and access/Private tasks/07 User stories](../../ui/storybook/stories/access/private-tasks/07-user-stories.stories.tsx) | `access/resources`, `tasks/properties` | unreviewed / production / fixtures | 13 / 7 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Master reconciliation inspected assignment-history recipient suggestions and manual-selection retention; existing stories do not establish the new assignment-history behavior. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. |
| [Getting started and access/Login, invitations, and access/Private tasks/00 Review guide](../../ui/storybook/stories/access/private-tasks/00-review-guide.stories.tsx) | `access/resources`, `tasks/properties` | unreviewed / guide / static | 1 / 0 | Review guide retained; explanatory content does not establish runtime or production coverage. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work. |
| [Getting started and access/Login, invitations, and access/Private tasks/01 Creation](../../ui/storybook/stories/access/private-tasks/01-creation.stories.tsx) | `access/resources`, `tasks/properties` | unreviewed / production / fixtures | 22 / 14 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Master reconciliation inspected assignment-history recipient suggestions and manual-selection retention; existing stories do not establish the new assignment-history behavior. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Creation visibility now defaults to hiding automated independent tasks, with a show agent-created tasks control and inbox participation exceptions. Source alignment reviewed; these fixture stories do not establish live server pagination or authorization. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work. |
| [Getting started and access/Login, invitations, and access/Private tasks/02 Sharing](../../ui/storybook/stories/access/private-tasks/02-sharing.stories.tsx) | `access/resources`, `tasks/properties` | unreviewed / production / fixtures | 26 / 10 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work. |
| [Getting started and access/Login, invitations, and access/Private tasks/03 Task actions](../../ui/storybook/stories/access/private-tasks/03-task-actions.stories.tsx) | `access/resources`, `tasks/properties` | unreviewed / production / fixtures | 11 / 7 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work. |
| [Getting started and access/Login, invitations, and access/Private tasks/04 References and blockers](../../ui/storybook/stories/access/private-tasks/04-references-and-blockers.stories.tsx) | `access/resources`, `tasks/properties` | unreviewed / production / fixtures | 12 / 5 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work. |
| [Getting started and access/Login, invitations, and access/Private tasks/05 Projects](../../ui/storybook/stories/access/private-tasks/05-projects.stories.tsx) | `access/resources`, `tasks/properties`, `projects/lifecycle` | unreviewed / production / fixtures | 19 / 12 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work. |
| [Getting started and access/Login, invitations, and access/Private tasks/06 Full product pages](../../ui/storybook/stories/access/private-tasks/06-full-product-pages.stories.tsx) | `access/resources`, `tasks/properties`, `projects/lifecycle` | unreviewed / production / fixtures | 21 / 12 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Master reconciliation inspected assignment-history recipient suggestions and manual-selection retention; existing stories do not establish the new assignment-history behavior. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Creation visibility now defaults to hiding automated independent tasks, with a show agent-created tasks control and inbox participation exceptions. Source alignment reviewed; these fixture stories do not establish live server pagination or authorization. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work. |
| [Getting started and access/Login, invitations, and access/Private tasks/07 User stories](../../ui/storybook/stories/access/private-tasks/07-user-stories.stories.tsx) | `access/resources`, `tasks/properties` | unreviewed / production / fixtures | 13 / 7 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Master reconciliation inspected assignment-history recipient suggestions and manual-selection retention; existing stories do not establish the new assignment-history behavior. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Creation visibility now defaults to hiding automated independent tasks, with a show agent-created tasks control and inbox participation exceptions. Source alignment reviewed; these fixture stories do not establish live server pagination or authorization. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work. |
### Companies and portability
@@ -63,27 +63,27 @@ Creation, assignment, lists, properties, comments, and completion.
| Story suite | Capabilities | Product / implementation / data | Stories / play functions | Review note |
| --- | --- | --- | --- | --- |
| [Tasks and conversations/Task creation and lifecycle/Paperclip/Assigned Backlog Safeguards](../../ui/storybook/stories/tasks/assigned-backlog-safeguards.stories.tsx) | `tasks/completion`, `recovery/diagnosis` | unreviewed / production / fixtures | 5 / 0 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. |
| [Tasks and conversations/Task creation and lifecycle/Product/Chat & Comments](../../ui/storybook/stories/tasks/chat-comments.stories.tsx) | `tasks/discussion`, `runs-adapters/runs` | unreviewed / production / fixtures | 6 / 0 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Master reconciliation inspected assignment-history recipient suggestions and manual-selection retention; existing stories do not establish the new assignment-history behavior. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. |
| [Tasks and conversations/Task creation and lifecycle/Tasks/Completed activity preview](../../ui/storybook/stories/tasks/completed-activity.stories.tsx) | `tasks/discussion`, `runs-adapters/runs` | current / production / fixtures | 8 / 0 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. |
| [Tasks and conversations/Task creation and lifecycle/Composer/Add menu](../../ui/storybook/stories/tasks/composer-add-menu.stories.tsx) | `tasks/create` | unreviewed / production / fixtures | 14 / 14 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Master reconciliation inspected assignment-history recipient suggestions and manual-selection retention; existing stories do not establish the new assignment-history behavior. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. |
| [Tasks and conversations/Task creation and lifecycle/Composer/Mobile assignee picker](../../ui/storybook/stories/tasks/composer-mobile-assignee.stories.tsx) | `tasks/create`, `runs-adapters/availability` | unreviewed / production / fixtures | 3 / 1 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. |
| [Tasks and conversations/Task creation and lifecycle/Composer/Model and effort picker](../../ui/storybook/stories/tasks/composer-model-picker.stories.tsx) | `tasks/create`, `runs-adapters/availability` | mixed / mixed / fixtures | 57 / 30 | Most examples use a local picker implementation; live picker examples use ComposerRunSettingsLiveStory. Do not count the whole suite as production parity. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. |
| [Tasks and conversations/Task creation and lifecycle/Product/Control Plane Surfaces](../../ui/storybook/stories/tasks/control-plane-surfaces.stories.tsx) | `tasks/organize`, `questions-and-approvals/governance`, `budgets-costs/budgets`, `activity/activity` | unreviewed / production / fixtures | 1 / 0 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. |
| [Tasks and conversations/Task creation and lifecycle/Product/Dialogs & Modals](../../ui/storybook/stories/tasks/dialogs-modals.stories.tsx) | `tasks/create`, `agents/hire`, `projects/lifecycle`, `goals/hierarchy` | unreviewed / production / fixtures | 17 / 2 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. |
| [Tasks and conversations/Task creation and lifecycle/External Objects](../../ui/storybook/stories/tasks/external-objects.stories.tsx) | `tasks/properties` | unreviewed / production / fixtures | 8 / 0 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. |
| [Tasks and conversations/Task creation and lifecycle/Product/Issue Management](../../ui/storybook/stories/tasks/issue-management.stories.tsx) | `tasks/properties`, `tasks/organize` | unreviewed / production / fixtures | 8 / 0 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. |
| [Tasks and conversations/Task creation and lifecycle/Components/Entity pickers/Mobile](../../ui/storybook/stories/tasks/mobile-entity-pickers.stories.tsx) | `tasks/create` | unreviewed / production / fixtures | 3 / 1 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. |
| [Tasks and conversations/Task creation and lifecycle/Composer/New task](../../ui/storybook/stories/tasks/new-task-composer.stories.tsx) | `tasks/create`, `workspaces/binding` | current / production / fixtures | 40 / 25 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. WorktreePicker, ReuseWorktree, CreateWithReusedWorktree and NewWorktreeAfterReuse exercise workspace selection and submitted fixture request values. Actual admission/binding and execution remain outside this story. |
| [Tasks and conversations/Task creation and lifecycle/Tasks/Runner activity preview](../../ui/storybook/stories/tasks/runner-activity.stories.tsx) | `tasks/discussion`, `runs-adapters/runs` | current / production / fixtures | 14 / 0 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. |
| [Tasks and conversations/Task creation and lifecycle/Paperclip/Successful Run Handoff](../../ui/storybook/stories/tasks/successful-run-handoff.stories.tsx) | `tasks/completion`, `recovery/diagnosis` | unreviewed / production / fixtures | 7 / 0 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Master reconciliation inspected assignment-history recipient suggestions and manual-selection retention; existing stories do not establish the new assignment-history behavior. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. |
| [Tasks and conversations/Task creation and lifecycle/Tasks/Task chat review fixes](../../ui/storybook/stories/tasks/task-chat-chain-of-thought.stories.tsx) | `tasks/discussion`, `runs-adapters/runs` | unreviewed / production / fixtures | 4 / 0 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. |
| [Tasks and conversations/Task creation and lifecycle/Task chat/Mobile streaming follow](../../ui/storybook/stories/tasks/task-chat-mobile-follow.stories.tsx) | `tasks/discussion` | unreviewed / production / fixtures | 1 / 0 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Master reconciliation inspected assignment-history recipient suggestions and manual-selection retention; existing stories do not establish the new assignment-history behavior. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. |
| [Tasks and conversations/Task creation and lifecycle/Product/Task chat/System notice](../../ui/storybook/stories/tasks/task-chat-system-notice.stories.tsx) | `tasks/discussion` | unreviewed / production / fixtures | 2 / 0 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. |
| [Tasks and conversations/Task creation and lifecycle/Tasks/Context notices](../../ui/storybook/stories/tasks/task-context-notices.stories.tsx) | `tasks/discussion` | unreviewed / production / fixtures | 1 / 1 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. |
| [Tasks and conversations/Task creation and lifecycle/Chat & Comments/Human identity/00 Review guide](../../ui/storybook/stories/tasks/thread-human-identity/00-evidence.stories.tsx) | `tasks/discussion` | unreviewed / guide / static | 1 / 0 | Review guide retained; explanatory content does not establish runtime or production coverage. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. |
| [Tasks and conversations/Task creation and lifecycle/Chat & Comments/Human identity/01 Components](../../ui/storybook/stories/tasks/thread-human-identity/01-components.stories.tsx) | `tasks/discussion` | unreviewed / production / fixtures | 5 / 2 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. |
| [Tasks and conversations/Task creation and lifecycle/Chat & Comments/Human identity/02 Mixed-author journey](../../ui/storybook/stories/tasks/thread-human-identity/02-task-journey.stories.tsx) | `tasks/discussion` | unreviewed / production / fixtures | 5 / 2 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Master reconciliation inspected assignment-history recipient suggestions and manual-selection retention; existing stories do not establish the new assignment-history behavior. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. |
| [Tasks and conversations/Task creation and lifecycle/Paperclip/Assigned Backlog Safeguards](../../ui/storybook/stories/tasks/assigned-backlog-safeguards.stories.tsx) | `tasks/completion`, `recovery/diagnosis` | unreviewed / production / fixtures | 5 / 0 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work. |
| [Tasks and conversations/Task creation and lifecycle/Product/Chat & Comments](../../ui/storybook/stories/tasks/chat-comments.stories.tsx) | `tasks/discussion`, `runs-adapters/runs` | unreviewed / production / fixtures | 6 / 0 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Master reconciliation inspected assignment-history recipient suggestions and manual-selection retention; existing stories do not establish the new assignment-history behavior. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work. |
| [Tasks and conversations/Task creation and lifecycle/Tasks/Completed activity preview](../../ui/storybook/stories/tasks/completed-activity.stories.tsx) | `tasks/discussion`, `runs-adapters/runs` | current / production / fixtures | 8 / 0 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work. |
| [Tasks and conversations/Task creation and lifecycle/Composer/Add menu](../../ui/storybook/stories/tasks/composer-add-menu.stories.tsx) | `tasks/create` | unreviewed / production / fixtures | 14 / 14 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Master reconciliation inspected assignment-history recipient suggestions and manual-selection retention; existing stories do not establish the new assignment-history behavior. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work. |
| [Tasks and conversations/Task creation and lifecycle/Composer/Mobile assignee picker](../../ui/storybook/stories/tasks/composer-mobile-assignee.stories.tsx) | `tasks/create`, `runs-adapters/availability` | unreviewed / production / fixtures | 3 / 1 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work. |
| [Tasks and conversations/Task creation and lifecycle/Composer/Model and effort picker](../../ui/storybook/stories/tasks/composer-model-picker.stories.tsx) | `tasks/create`, `runs-adapters/availability` | mixed / mixed / fixtures | 57 / 30 | Most examples use a local picker implementation; live picker examples use ComposerRunSettingsLiveStory. Do not count the whole suite as production parity. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work. |
| [Tasks and conversations/Task creation and lifecycle/Product/Control Plane Surfaces](../../ui/storybook/stories/tasks/control-plane-surfaces.stories.tsx) | `tasks/organize`, `questions-and-approvals/governance`, `budgets-costs/budgets`, `activity/activity` | unreviewed / production / fixtures | 1 / 0 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work. |
| [Tasks and conversations/Task creation and lifecycle/Product/Dialogs & Modals](../../ui/storybook/stories/tasks/dialogs-modals.stories.tsx) | `tasks/create`, `agents/hire`, `projects/lifecycle`, `goals/hierarchy` | unreviewed / production / fixtures | 17 / 2 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work. |
| [Tasks and conversations/Task creation and lifecycle/External Objects](../../ui/storybook/stories/tasks/external-objects.stories.tsx) | `tasks/properties` | unreviewed / production / fixtures | 8 / 0 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Creation visibility now defaults to hiding automated independent tasks, with a show agent-created tasks control and inbox participation exceptions. Source alignment reviewed; these fixture stories do not establish live server pagination or authorization. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work. |
| [Tasks and conversations/Task creation and lifecycle/Product/Issue Management](../../ui/storybook/stories/tasks/issue-management.stories.tsx) | `tasks/properties`, `tasks/organize` | unreviewed / production / fixtures | 11 / 3 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Creation visibility now defaults to hiding automated independent tasks, with a show agent-created tasks control and inbox participation exceptions. Source alignment reviewed; these fixture stories do not establish live server pagination or authorization. Focused creation-visibility stories mount the production collection with simulated hierarchy reads and assert hidden roots, opt-in inclusion, and the unchecked filter control. Creation visibility examples and fixture setup now live in a support module so the surface matrix stays below 1000 lines; exported story IDs are unchanged. Creation visibility now shares the subscribed preference across modern and legacy controls; hierarchy child reads share a bounded rendering budget. Source alignment inspected; server behavior is tested separately. Hierarchy fetch and rendering budgets are separate; loaded context remains during paging. The large-tree UI regression exercises delayed reads in both list interfaces. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work. |
| [Tasks and conversations/Task creation and lifecycle/Components/Entity pickers/Mobile](../../ui/storybook/stories/tasks/mobile-entity-pickers.stories.tsx) | `tasks/create` | unreviewed / production / fixtures | 3 / 1 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work. |
| [Tasks and conversations/Task creation and lifecycle/Composer/New task](../../ui/storybook/stories/tasks/new-task-composer.stories.tsx) | `tasks/create`, `workspaces/binding` | current / production / fixtures | 40 / 25 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. WorktreePicker, ReuseWorktree, CreateWithReusedWorktree and NewWorktreeAfterReuse exercise workspace selection and submitted fixture request values. Actual admission/binding and execution remain outside this story. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work. |
| [Tasks and conversations/Task creation and lifecycle/Tasks/Runner activity preview](../../ui/storybook/stories/tasks/runner-activity.stories.tsx) | `tasks/discussion`, `runs-adapters/runs` | current / production / fixtures | 14 / 0 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work. |
| [Tasks and conversations/Task creation and lifecycle/Paperclip/Successful Run Handoff](../../ui/storybook/stories/tasks/successful-run-handoff.stories.tsx) | `tasks/completion`, `recovery/diagnosis` | unreviewed / production / fixtures | 7 / 0 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Master reconciliation inspected assignment-history recipient suggestions and manual-selection retention; existing stories do not establish the new assignment-history behavior. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work. |
| [Tasks and conversations/Task creation and lifecycle/Tasks/Task chat review fixes](../../ui/storybook/stories/tasks/task-chat-chain-of-thought.stories.tsx) | `tasks/discussion`, `runs-adapters/runs` | unreviewed / production / fixtures | 4 / 0 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work. |
| [Tasks and conversations/Task creation and lifecycle/Task chat/Mobile streaming follow](../../ui/storybook/stories/tasks/task-chat-mobile-follow.stories.tsx) | `tasks/discussion` | unreviewed / production / fixtures | 1 / 0 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Master reconciliation inspected assignment-history recipient suggestions and manual-selection retention; existing stories do not establish the new assignment-history behavior. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work. |
| [Tasks and conversations/Task creation and lifecycle/Product/Task chat/System notice](../../ui/storybook/stories/tasks/task-chat-system-notice.stories.tsx) | `tasks/discussion` | unreviewed / production / fixtures | 2 / 0 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work. |
| [Tasks and conversations/Task creation and lifecycle/Tasks/Context notices](../../ui/storybook/stories/tasks/task-context-notices.stories.tsx) | `tasks/discussion` | unreviewed / production / fixtures | 1 / 1 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work. |
| [Tasks and conversations/Task creation and lifecycle/Chat & Comments/Human identity/00 Review guide](../../ui/storybook/stories/tasks/thread-human-identity/00-evidence.stories.tsx) | `tasks/discussion` | unreviewed / guide / static | 1 / 0 | Review guide retained; explanatory content does not establish runtime or production coverage. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work. |
| [Tasks and conversations/Task creation and lifecycle/Chat & Comments/Human identity/01 Components](../../ui/storybook/stories/tasks/thread-human-identity/01-components.stories.tsx) | `tasks/discussion` | unreviewed / production / fixtures | 5 / 2 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work. |
| [Tasks and conversations/Task creation and lifecycle/Chat & Comments/Human identity/02 Mixed-author journey](../../ui/storybook/stories/tasks/thread-human-identity/02-task-journey.stories.tsx) | `tasks/discussion` | unreviewed / production / fixtures | 5 / 2 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Master reconciliation inspected assignment-history recipient suggestions and manual-selection retention; existing stories do not establish the new assignment-history behavior. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work. |
### Delegation, dependencies, and signoff
@@ -95,23 +95,23 @@ Child work, prerequisites, reviewers, and task-tree controls.
| --- | --- | --- | --- | --- |
| [Tasks and conversations/Delegation, dependencies, and signoff/Product/Decisions/Stalled review actions](../../ui/storybook/stories/task-coordination/issue-review-panel.stories.tsx) | `task-coordination/signoff` | unreviewed / production / fixtures | 2 / 0 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. |
| [Tasks and conversations/Delegation, dependencies, and signoff/Product/Issue Monitor surfaces](../../ui/storybook/stories/task-coordination/monitor-surfaces.stories.tsx) | `task-coordination/tree-control` | unreviewed / production / fixtures | 1 / 0 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. |
| [Tasks and conversations/Delegation, dependencies, and signoff/UX Labs/Tasks Created From a Task](../../ui/storybook/stories/task-coordination/originating-tasks.stories.tsx) | `task-coordination/delegation`, `projects/task-context` | unreviewed / production / fixtures | 14 / 0 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Master reconciliation inspected assignment-history recipient suggestions and manual-selection retention; existing stories do not establish the new assignment-history behavior. |
| [Tasks and conversations/Delegation, dependencies, and signoff/UX Labs/Sub-issues Workflow Checklist](../../ui/storybook/stories/task-coordination/sub-issues-workflow.stories.tsx) | `task-coordination/dependencies`, `task-coordination/delegation` | unreviewed / production / fixtures | 1 / 0 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. |
| [Tasks and conversations/Delegation, dependencies, and signoff/UX Labs/Tasks Created From a Task](../../ui/storybook/stories/task-coordination/originating-tasks.stories.tsx) | `task-coordination/delegation`, `projects/task-context` | unreviewed / production / fixtures | 14 / 0 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Master reconciliation inspected assignment-history recipient suggestions and manual-selection retention; existing stories do not establish the new assignment-history behavior. Creation visibility now defaults to hiding automated independent tasks, with a Show agent-created tasks control and inbox participation exceptions. Source alignment reviewed; these fixture stories do not establish live server pagination or authorization. |
| [Tasks and conversations/Delegation, dependencies, and signoff/UX Labs/Sub-issues Workflow Checklist](../../ui/storybook/stories/task-coordination/sub-issues-workflow.stories.tsx) | `task-coordination/dependencies`, `task-coordination/delegation` | unreviewed / production / fixtures | 1 / 0 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Creation visibility now defaults to hiding automated independent tasks, with a Show agent-created tasks control and inbox participation exceptions. Source alignment reviewed; these fixture stories do not establish live server pagination or authorization. Creation visibility now shares the subscribed preference across modern and legacy controls; hierarchy child reads share a bounded rendering budget. Source alignment inspected; server behavior is tested separately. Hierarchy fetch and rendering budgets are separate; loaded context remains during paging. The large-tree UI regression exercises delayed reads in both list interfaces. |
| [Tasks and conversations/Delegation, dependencies, and signoff/Product/Task Watchdog surfaces](../../ui/storybook/stories/task-coordination/task-watchdog-surfaces.stories.tsx) | `task-coordination/tree-control` | unreviewed / production / fixtures | 1 / 0 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. |
### Inbox, decisions, and search
Personal triage, decision queues, unread/blocked views, and search.
Personal triage, decision queues, unread/blocked views, search, and personal task toasts.
[Feature recipe](../feature-map/inbox-search.md)
| Story suite | Capabilities | Product / implementation / data | Stories / play functions | Review note |
| --- | --- | --- | --- | --- |
| [Tasks and conversations/Inbox, decisions, and search/Product/Inbox/Blocked tab](../../ui/storybook/stories/inbox-search/blocked-inbox.stories.tsx) | `inbox-search/triage`, `recovery/diagnosis` | unreviewed / production / fixtures | 5 / 0 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. |
| [Tasks and conversations/Inbox, decisions, and search/Decisions/DecisionCard](../../ui/storybook/stories/inbox-search/decision-card.stories.tsx) | `inbox-search/decisions` | unreviewed / production / fixtures | 9 / 0 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. |
| [Tasks and conversations/Inbox, decisions, and search/Pages/Decisions Desk](../../ui/storybook/stories/inbox-search/decisions-desk.stories.tsx) | `inbox-search/decisions` | unreviewed / production / fixtures | 6 / 0 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. |
| [Tasks and conversations/Inbox, decisions, and search/Product/Search & Command K](../../ui/storybook/stories/inbox-search/search.stories.tsx) | `inbox-search/search` | unreviewed / prototype / fixtures | 1 / 0 | Local search-page composition mounts production result components; does not establish parity with the production Search route. |
| [Tasks and conversations/Inbox, decisions, and search/Pages/Decisions](../../ui/storybook/stories/inbox-search/what-needs-me.stories.tsx) | `inbox-search/decisions` | unreviewed / production / fixtures | 13 / 0 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. |
| [Tasks and conversations/Inbox, decisions, and search/Product/Inbox/Blocked tab](../../ui/storybook/stories/inbox-search/blocked-inbox.stories.tsx) | `inbox-search/triage`, `recovery/diagnosis` | unreviewed / production / fixtures | 5 / 0 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Creation visibility now defaults to hiding automated independent tasks, with a show agent-created tasks control and inbox participation exceptions. Source alignment reviewed; these fixture stories do not establish live server pagination or authorization. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work. |
| [Tasks and conversations/Inbox, decisions, and search/Decisions/DecisionCard](../../ui/storybook/stories/inbox-search/decision-card.stories.tsx) | `inbox-search/decisions` | unreviewed / production / fixtures | 9 / 0 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work. |
| [Tasks and conversations/Inbox, decisions, and search/Pages/Decisions Desk](../../ui/storybook/stories/inbox-search/decisions-desk.stories.tsx) | `inbox-search/decisions` | unreviewed / production / fixtures | 6 / 0 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work. |
| [Tasks and conversations/Inbox, decisions, and search/Product/Search & Command K](../../ui/storybook/stories/inbox-search/search.stories.tsx) | `inbox-search/search` | unreviewed / prototype / fixtures | 1 / 0 | Local search-page composition mounts production result components; does not establish parity with the production Search route. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work. |
| [Tasks and conversations/Inbox, decisions, and search/Pages/Decisions](../../ui/storybook/stories/inbox-search/what-needs-me.stories.tsx) | `inbox-search/decisions` | unreviewed / production / fixtures | 13 / 0 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work. |
### Agent conversations and project handoff
@@ -141,7 +141,7 @@ Question/plan responses, formal approvals, and app-tool review.
| [Tasks and conversations/Questions and approvals/Chat & Comments/Issue Thread Interactions](../../ui/storybook/stories/questions-and-approvals/issue-thread-interactions.stories.tsx) | `questions-and-approvals/questions`, `questions-and-approvals/confirmations`, `questions-and-approvals/audience`, `questions-and-approvals/plan-review`, `questions-and-approvals/continuation` | unreviewed / production / fixtures | 53 / 0 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Master reconciliation inspected assignment-history recipient suggestions and manual-selection retention; existing stories do not establish the new assignment-history behavior. Plan approval Pending, Confirmed, ExpiredByTargetChange and ResumeFailed states use shipped interaction cards. The continuation association covers accepted-but-resume-failed presentation only; no successful resumption, retry or duplicate-suppression proof. |
| [Tasks and conversations/Questions and approvals/Chat & Comments/Rich ACP interactions](../../ui/storybook/stories/questions-and-approvals/rich-acp-interactions.stories.tsx) | `questions-and-approvals/questions`, `questions-and-approvals/confirmations`, `questions-and-approvals/audience` | unreviewed / production / fixtures | 12 / 8 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. |
| [Tasks and conversations/Questions and approvals/Composer/Interaction above composer](../../ui/storybook/stories/questions-and-approvals/task-chat-interaction-above-composer.stories.tsx) | `questions-and-approvals/questions`, `questions-and-approvals/confirmations`, `questions-and-approvals/audience` | current / production / fixtures | 15 / 5 | Corrected local dismissal/send harness: questions leave no pending badge; confirmations retain reopen. Production cards/composer; persisted dismissal is covered separately by unanswered-question fixtures. Master reconciliation inspected assignment-history recipient suggestions and manual-selection retention; existing stories do not establish the new assignment-history behavior. |
| [Tasks and conversations/Questions and approvals/Chat & Comments/Task Chat Unanswered Questions](../../ui/storybook/stories/questions-and-approvals/task-chat-unanswered-questions.stories.tsx) | `questions-and-approvals/dismiss-and-reopen`, `tasks/discussion` | unreviewed / production / fixtures | 6 / 1 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Master reconciliation inspected assignment-history recipient suggestions and manual-selection retention; existing stories do not establish the new assignment-history behavior. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. |
| [Tasks and conversations/Questions and approvals/Chat & Comments/Task Chat Unanswered Questions](../../ui/storybook/stories/questions-and-approvals/task-chat-unanswered-questions.stories.tsx) | `questions-and-approvals/dismiss-and-reopen`, `tasks/discussion` | unreviewed / production / fixtures | 6 / 1 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Master reconciliation inspected assignment-history recipient suggestions and manual-selection retention; existing stories do not establish the new assignment-history behavior. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work. |
### Steering and queued messages
@@ -206,14 +206,14 @@ Agent identity, instructions, reporting lines, lifecycle, and built-ins.
| [Agents and reusable capabilities/Hiring, configuration, and organization/Onboarding/External agent invitation/Components](../../ui/storybook/stories/agents/external-agent-invite/components.stories.tsx) | `agents/hire`, `access/invitations` | unreviewed / production / fixtures | 8 / 0 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. |
| [Agents and reusable capabilities/Hiring, configuration, and organization/Onboarding/External agent invitation/Journeys](../../ui/storybook/stories/agents/external-agent-invite/journeys.stories.tsx) | `agents/hire`, `access/invitations` | unreviewed / production / fixtures | 20 / 4 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. |
| [Agents and reusable capabilities/Hiring, configuration, and organization/Onboarding/New agent](../../ui/storybook/stories/agents/new-agent-onboarding.stories.tsx) | `agents/hire` | historical / prototype / fixtures | 37 / 1 | Retained local wizard predates production ui/src/components/new-agent flow; shared fields do not make the wizard current. |
| [Agents and reusable capabilities/Hiring, configuration, and organization/Primary Agent/00 Review guide](../../ui/storybook/stories/agents/primary-agent/00-review-guide.stories.tsx) | `agents/primary-agent`, `tasks/create`, `agent-chat/discovery` | unreviewed / guide / static | 1 / 0 | Review guide retained; explanatory content does not establish runtime or production coverage. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Primary choice, replacement confirmation, unavailable states and task/chat fallback presentation use local presentation-provider callbacks. Production preference persistence and default-resolution precedence remain unverified by this suite. |
| [Agents and reusable capabilities/Hiring, configuration, and organization/Primary Agent/01 Components](../../ui/storybook/stories/agents/primary-agent/01-components.stories.tsx) | `agents/primary-agent`, `tasks/create`, `agent-chat/discovery` | unreviewed / production / fixtures | 5 / 0 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Primary choice, replacement confirmation, unavailable states and task/chat fallback presentation use local presentation-provider callbacks. Production preference persistence and default-resolution precedence remain unverified by this suite. |
| [Agents and reusable capabilities/Hiring, configuration, and organization/Primary Agent/02 Sidebar](../../ui/storybook/stories/agents/primary-agent/02-sidebar.stories.tsx) | `agents/primary-agent`, `tasks/create`, `agent-chat/discovery` | unreviewed / production / fixtures | 12 / 1 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Primary choice, replacement confirmation, unavailable states and task/chat fallback presentation use local presentation-provider callbacks. Production preference persistence and default-resolution precedence remain unverified by this suite. |
| [Agents and reusable capabilities/Hiring, configuration, and organization/Primary Agent/03 Agents](../../ui/storybook/stories/agents/primary-agent/03-agents.stories.tsx) | `agents/primary-agent`, `tasks/create`, `agent-chat/discovery` | unreviewed / production / fixtures | 14 / 0 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Primary choice, replacement confirmation, unavailable states and task/chat fallback presentation use local presentation-provider callbacks. Production preference persistence and default-resolution precedence remain unverified by this suite. |
| [Agents and reusable capabilities/Hiring, configuration, and organization/Primary Agent/04 New task](../../ui/storybook/stories/agents/primary-agent/04-new-task.stories.tsx) | `agents/primary-agent`, `tasks/create`, `agent-chat/discovery` | unreviewed / production / fixtures | 9 / 0 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Primary choice, replacement confirmation, unavailable states and task/chat fallback presentation use local presentation-provider callbacks. Production preference persistence and default-resolution precedence remain unverified by this suite. |
| [Agents and reusable capabilities/Hiring, configuration, and organization/Primary Agent/05 Chat](../../ui/storybook/stories/agents/primary-agent/05-chat.stories.tsx) | `agents/primary-agent`, `tasks/create`, `agent-chat/discovery` | unreviewed / production / fixtures | 8 / 0 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Primary choice, replacement confirmation, unavailable states and task/chat fallback presentation use local presentation-provider callbacks. Production preference persistence and default-resolution precedence remain unverified by this suite. |
| [Agents and reusable capabilities/Hiring, configuration, and organization/Primary Agent/06 Journeys](../../ui/storybook/stories/agents/primary-agent/06-journeys.stories.tsx) | `agents/primary-agent`, `tasks/create`, `agent-chat/discovery` | unreviewed / production / fixtures | 11 / 11 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Primary choice, replacement confirmation, unavailable states and task/chat fallback presentation use local presentation-provider callbacks. Production preference persistence and default-resolution precedence remain unverified by this suite. |
| [Agents and reusable capabilities/Hiring, configuration, and organization/Primary Agent/07 Confirmation](../../ui/storybook/stories/agents/primary-agent/07-confirmation.stories.tsx) | `agents/primary-agent`, `tasks/create`, `agent-chat/discovery` | unreviewed / production / fixtures | 4 / 1 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Primary choice, replacement confirmation, unavailable states and task/chat fallback presentation use local presentation-provider callbacks. Production preference persistence and default-resolution precedence remain unverified by this suite. |
| [Agents and reusable capabilities/Hiring, configuration, and organization/Primary Agent/00 Review guide](../../ui/storybook/stories/agents/primary-agent/00-review-guide.stories.tsx) | `agents/primary-agent`, `tasks/create`, `agent-chat/discovery` | unreviewed / guide / static | 1 / 0 | Review guide retained; explanatory content does not establish runtime or production coverage. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Primary choice, replacement confirmation, unavailable states and task/chat fallback presentation use local presentation-provider callbacks. Production preference persistence and default-resolution precedence remain unverified by this suite. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work. |
| [Agents and reusable capabilities/Hiring, configuration, and organization/Primary Agent/01 Components](../../ui/storybook/stories/agents/primary-agent/01-components.stories.tsx) | `agents/primary-agent`, `tasks/create`, `agent-chat/discovery` | unreviewed / production / fixtures | 5 / 0 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Primary choice, replacement confirmation, unavailable states and task/chat fallback presentation use local presentation-provider callbacks. Production preference persistence and default-resolution precedence remain unverified by this suite. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work. |
| [Agents and reusable capabilities/Hiring, configuration, and organization/Primary Agent/02 Sidebar](../../ui/storybook/stories/agents/primary-agent/02-sidebar.stories.tsx) | `agents/primary-agent`, `tasks/create`, `agent-chat/discovery` | unreviewed / production / fixtures | 12 / 1 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Primary choice, replacement confirmation, unavailable states and task/chat fallback presentation use local presentation-provider callbacks. Production preference persistence and default-resolution precedence remain unverified by this suite. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work. |
| [Agents and reusable capabilities/Hiring, configuration, and organization/Primary Agent/03 Agents](../../ui/storybook/stories/agents/primary-agent/03-agents.stories.tsx) | `agents/primary-agent`, `tasks/create`, `agent-chat/discovery` | unreviewed / production / fixtures | 14 / 0 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Primary choice, replacement confirmation, unavailable states and task/chat fallback presentation use local presentation-provider callbacks. Production preference persistence and default-resolution precedence remain unverified by this suite. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work. |
| [Agents and reusable capabilities/Hiring, configuration, and organization/Primary Agent/04 New task](../../ui/storybook/stories/agents/primary-agent/04-new-task.stories.tsx) | `agents/primary-agent`, `tasks/create`, `agent-chat/discovery` | unreviewed / production / fixtures | 9 / 0 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Primary choice, replacement confirmation, unavailable states and task/chat fallback presentation use local presentation-provider callbacks. Production preference persistence and default-resolution precedence remain unverified by this suite. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work. |
| [Agents and reusable capabilities/Hiring, configuration, and organization/Primary Agent/05 Chat](../../ui/storybook/stories/agents/primary-agent/05-chat.stories.tsx) | `agents/primary-agent`, `tasks/create`, `agent-chat/discovery` | unreviewed / production / fixtures | 8 / 0 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Primary choice, replacement confirmation, unavailable states and task/chat fallback presentation use local presentation-provider callbacks. Production preference persistence and default-resolution precedence remain unverified by this suite. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work. |
| [Agents and reusable capabilities/Hiring, configuration, and organization/Primary Agent/06 Journeys](../../ui/storybook/stories/agents/primary-agent/06-journeys.stories.tsx) | `agents/primary-agent`, `tasks/create`, `agent-chat/discovery` | unreviewed / production / fixtures | 11 / 11 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Primary choice, replacement confirmation, unavailable states and task/chat fallback presentation use local presentation-provider callbacks. Production preference persistence and default-resolution precedence remain unverified by this suite. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work. |
| [Agents and reusable capabilities/Hiring, configuration, and organization/Primary Agent/07 Confirmation](../../ui/storybook/stories/agents/primary-agent/07-confirmation.stories.tsx) | `agents/primary-agent`, `tasks/create`, `agent-chat/discovery` | unreviewed / production / fixtures | 4 / 1 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Primary choice, replacement confirmation, unavailable states and task/chat fallback presentation use local presentation-provider callbacks. Production preference persistence and default-resolution precedence remain unverified by this suite. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work. |
| [Agents and reusable capabilities/Hiring, configuration, and organization/Summaries/SummarySlotCard](../../ui/storybook/stories/agents/summary-slot-card.stories.tsx) | `agents/built-in` | unreviewed / production / fixtures | 15 / 0 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. |
### Runs, harnesses, and model accounts
@@ -303,9 +303,9 @@ Provisioning, task bindings, services/logs, Git/files, and closure.
| Story suite | Capabilities | Product / implementation / data | Stories / play functions | Review note |
| --- | --- | --- | --- | --- |
| [Projects and execution/Workspaces, services, and files/Tasks/Browser Use/Task activity](../../ui/storybook/stories/workspaces/browser-use-activity.stories.tsx) | `workspaces/services`, `tasks/discussion` | unreviewed / production / fixtures | 7 / 0 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Task-workspace reconciliation reviewed the expanded workspace recipe; these examples do not establish durable task-folder continuity, repository authorization or sandbox admission. The workspace recipe now requires child boundary, safe reopen and checkpoint ancestry controls; these backend checks are not established by this fixture. The provisioning recipe requires controller script denial for remote selections and copy-only local source choices, including retained denial through metadata changes and reopening; these fixtures do not verify execution placement. Canonical default provisioning follows configured policy, primary, creation time and ID; these fixtures do not run source hooks or establish this backend precedence. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. |
| [Projects and execution/Workspaces, services, and files/Tasks/Browser Use/Footer](../../ui/storybook/stories/workspaces/browser-use-footer.stories.tsx) | `workspaces/services`, `tasks/discussion` | unreviewed / production / fixtures | 21 / 2 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Task-workspace reconciliation reviewed the expanded workspace recipe; these examples do not establish durable task-folder continuity, repository authorization or sandbox admission. The workspace recipe now requires child boundary, safe reopen and checkpoint ancestry controls; these backend checks are not established by this fixture. The provisioning recipe requires controller script denial for remote selections and copy-only local source choices, including retained denial through metadata changes and reopening; these fixtures do not verify execution placement. Canonical default provisioning follows configured policy, primary, creation time and ID; these fixtures do not run source hooks or establish this backend precedence. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. |
| [Projects and execution/Workspaces, services, and files/Tasks/Browser Use/Panel](../../ui/storybook/stories/workspaces/browser-use.stories.tsx) | `workspaces/services`, `tasks/discussion` | unreviewed / production / fixtures | 28 / 3 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Task-workspace reconciliation reviewed the expanded workspace recipe; these examples do not establish durable task-folder continuity, repository authorization or sandbox admission. The workspace recipe now requires child boundary, safe reopen and checkpoint ancestry controls; these backend checks are not established by this fixture. The provisioning recipe requires controller script denial for remote selections and copy-only local source choices, including retained denial through metadata changes and reopening; these fixtures do not verify execution placement. Canonical default provisioning follows configured policy, primary, creation time and ID; these fixtures do not run source hooks or establish this backend precedence. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. |
| [Projects and execution/Workspaces, services, and files/Tasks/Browser Use/Task activity](../../ui/storybook/stories/workspaces/browser-use-activity.stories.tsx) | `workspaces/services`, `tasks/discussion` | unreviewed / production / fixtures | 7 / 0 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Task-workspace reconciliation reviewed the expanded workspace recipe; these examples do not establish durable task-folder continuity, repository authorization or sandbox admission. The workspace recipe now requires child boundary, safe reopen and checkpoint ancestry controls; these backend checks are not established by this fixture. The provisioning recipe requires controller script denial for remote selections and copy-only local source choices, including retained denial through metadata changes and reopening; these fixtures do not verify execution placement. Canonical default provisioning follows configured policy, primary, creation time and ID; these fixtures do not run source hooks or establish this backend precedence. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work. |
| [Projects and execution/Workspaces, services, and files/Tasks/Browser Use/Footer](../../ui/storybook/stories/workspaces/browser-use-footer.stories.tsx) | `workspaces/services`, `tasks/discussion` | unreviewed / production / fixtures | 21 / 2 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Task-workspace reconciliation reviewed the expanded workspace recipe; these examples do not establish durable task-folder continuity, repository authorization or sandbox admission. The workspace recipe now requires child boundary, safe reopen and checkpoint ancestry controls; these backend checks are not established by this fixture. The provisioning recipe requires controller script denial for remote selections and copy-only local source choices, including retained denial through metadata changes and reopening; these fixtures do not verify execution placement. Canonical default provisioning follows configured policy, primary, creation time and ID; these fixtures do not run source hooks or establish this backend precedence. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work. |
| [Projects and execution/Workspaces, services, and files/Tasks/Browser Use/Panel](../../ui/storybook/stories/workspaces/browser-use.stories.tsx) | `workspaces/services`, `tasks/discussion` | unreviewed / production / fixtures | 28 / 3 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Task-workspace reconciliation reviewed the expanded workspace recipe; these examples do not establish durable task-folder continuity, repository authorization or sandbox admission. The workspace recipe now requires child boundary, safe reopen and checkpoint ancestry controls; these backend checks are not established by this fixture. The provisioning recipe requires controller script denial for remote selections and copy-only local source choices, including retained denial through metadata changes and reopening; these fixtures do not verify execution placement. Canonical default provisioning follows configured policy, primary, creation time and ID; these fixtures do not run source hooks or establish this backend precedence. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work. |
| [Projects and execution/Workspaces, services, and files/Components/SearchableSelect/Workspace picker](../../ui/storybook/stories/workspaces/searchable-select.stories.tsx) | `workspaces/binding` | unreviewed / production / fixtures | 9 / 0 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Task-workspace reconciliation reviewed the expanded workspace recipe; these examples do not establish durable task-folder continuity, repository authorization or sandbox admission. The workspace recipe now requires child boundary, safe reopen and checkpoint ancestry controls; these backend checks are not established by this fixture. The provisioning recipe requires controller script denial for remote selections and copy-only local source choices, including retained denial through metadata changes and reopening; these fixtures do not verify execution placement. Canonical default provisioning follows configured policy, primary, creation time and ID; these fixtures do not run source hooks or establish this backend precedence. |
| [Projects and execution/Workspaces, services, and files/Issue/Workspace File Browser](../../ui/storybook/stories/workspaces/workspace-file-browser.stories.tsx) | `workspaces/files-git` | unreviewed / production / fixtures | 6 / 0 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Task-workspace reconciliation reviewed the expanded workspace recipe; these examples do not establish durable task-folder continuity, repository authorization or sandbox admission. The workspace recipe now requires child boundary, safe reopen and checkpoint ancestry controls; these backend checks are not established by this fixture. The provisioning recipe requires controller script denial for remote selections and copy-only local source choices, including retained denial through metadata changes and reopening; these fixtures do not verify execution placement. Canonical default provisioning follows configured policy, primary, creation time and ID; these fixtures do not run source hooks or establish this backend precedence. |
| [Projects and execution/Workspaces, services, and files/Workspaces/Runtime provisioning status](../../ui/storybook/stories/workspaces/workspace-runtime-provisioning.stories.tsx) | `workspaces/provisioning` | unreviewed / production / fixtures | 6 / 0 | Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Task-workspace reconciliation reviewed ExecutionWorkspaceDetail null-project handling. This suite mounts only the unchanged RuntimeProvisionStatusValue inside a local context row; it does not exercise the full detail page or projectless queries. The workspace recipe now requires child boundary, safe reopen and checkpoint ancestry controls; these backend checks are not established by this fixture. The provisioning recipe requires controller script denial for remote selections and copy-only local source choices, including retained denial through metadata changes and reopening; these fixtures do not verify execution placement. Canonical default provisioning follows configured policy, primary, creation time and ID; these fixtures do not run source hooks or establish this backend precedence. |
@@ -604,6 +604,7 @@ References are navigation links, not proof of parity. An absent link means no ca
- `inbox-search/triage`: [Tasks and conversations/Inbox, decisions, and search/Product/Inbox/Blocked tab](../../ui/storybook/stories/inbox-search/blocked-inbox.stories.tsx) (unreviewed)
- `inbox-search/decisions`: [Tasks and conversations/Inbox, decisions, and search/Decisions/DecisionCard](../../ui/storybook/stories/inbox-search/decision-card.stories.tsx) (unreviewed), [Tasks and conversations/Inbox, decisions, and search/Pages/Decisions Desk](../../ui/storybook/stories/inbox-search/decisions-desk.stories.tsx) (unreviewed), [Tasks and conversations/Inbox, decisions, and search/Pages/Decisions](../../ui/storybook/stories/inbox-search/what-needs-me.stories.tsx) (unreviewed)
- `inbox-search/search`: [Tasks and conversations/Inbox, decisions, and search/Product/Search & Command K](../../ui/storybook/stories/inbox-search/search.stories.tsx) (unreviewed)
- `inbox-search/toasts`: No cataloged story.
- `agent-chat/discovery`: [Tasks and conversations/Agent conversations and project handoff/Design explorations/Agent chat sidebar/Pages](../../ui/storybook/stories/agent-chat/agent-chat-sidebar.stories.tsx) (unreviewed), [Tasks and conversations/Agent conversations and project handoff/Design explorations/Agent chat](../../ui/storybook/stories/agent-chat/agent-chat.stories.tsx) (mixed), [Tasks and conversations/Agent conversations and project handoff/Design explorations/Agent chat sidebar/Components](../../ui/storybook/stories/agent-chat/agent-conversation-sidebar.stories.tsx) (current), [Tasks and conversations/Agent conversations and project handoff/Design explorations/Chat entry](../../ui/storybook/stories/agent-chat/chat-entry.stories.tsx) (historical), [Agents and reusable capabilities/Hiring, configuration, and organization/Primary Agent/00 Review guide](../../ui/storybook/stories/agents/primary-agent/00-review-guide.stories.tsx) (unreviewed), [Agents and reusable capabilities/Hiring, configuration, and organization/Primary Agent/01 Components](../../ui/storybook/stories/agents/primary-agent/01-components.stories.tsx) (unreviewed), [Agents and reusable capabilities/Hiring, configuration, and organization/Primary Agent/02 Sidebar](../../ui/storybook/stories/agents/primary-agent/02-sidebar.stories.tsx) (unreviewed), [Agents and reusable capabilities/Hiring, configuration, and organization/Primary Agent/03 Agents](../../ui/storybook/stories/agents/primary-agent/03-agents.stories.tsx) (unreviewed), [Agents and reusable capabilities/Hiring, configuration, and organization/Primary Agent/04 New task](../../ui/storybook/stories/agents/primary-agent/04-new-task.stories.tsx) (unreviewed), [Agents and reusable capabilities/Hiring, configuration, and organization/Primary Agent/05 Chat](../../ui/storybook/stories/agents/primary-agent/05-chat.stories.tsx) (unreviewed), [Agents and reusable capabilities/Hiring, configuration, and organization/Primary Agent/06 Journeys](../../ui/storybook/stories/agents/primary-agent/06-journeys.stories.tsx) (unreviewed), [Agents and reusable capabilities/Hiring, configuration, and organization/Primary Agent/07 Confirmation](../../ui/storybook/stories/agents/primary-agent/07-confirmation.stories.tsx) (unreviewed)
- `agent-chat/history`: [Tasks and conversations/Agent conversations and project handoff/Design explorations/Agent chat sidebar/Pages](../../ui/storybook/stories/agent-chat/agent-chat-sidebar.stories.tsx) (unreviewed), [Tasks and conversations/Questions and approvals/Chat & Comments/Agent Chat Unanswered Questions](../../ui/storybook/stories/questions-and-approvals/agent-chat-unanswered-questions.stories.tsx) (unreviewed), [Tasks and conversations/Agent conversations and project handoff/Design explorations/Agent chat](../../ui/storybook/stories/agent-chat/agent-chat.stories.tsx) (mixed), [Tasks and conversations/Agent conversations and project handoff/Design explorations/Agent chat sidebar/Components](../../ui/storybook/stories/agent-chat/agent-conversation-sidebar.stories.tsx) (current), [Tasks and conversations/Agent conversations and project handoff/Design explorations/Chat entry](../../ui/storybook/stories/agent-chat/chat-entry.stories.tsx) (historical)
- `agent-chat/handoff`: [Tasks and conversations/Agent conversations and project handoff/Design explorations/Agent chat](../../ui/storybook/stories/agent-chat/agent-chat.stories.tsx) (mixed)
+106 -105
View File
@@ -10,7 +10,7 @@
"ui/storybook/generated/feature-index.json",
"ui/storybook/support/feature-map/FeatureOverview.tsx"
],
"fingerprint": "451bee6238c89f00e77fa9fdc5f86c621afffdf9809c4a9ac9cbf1f3f4f60b78"
"fingerprint": "6bdb0d9cc1f9abb1d9b1c1d7b4652ee4f4cf5c9c5d939069dfabef70ed731df3"
},
"entries": [
{
@@ -1185,7 +1185,7 @@
"status": "unreviewed",
"implementation": "production",
"boundary": "fixtures",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts.",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work.",
"reviewedAt": "2026-10-13",
"sources": [
"maps/feature-map/recovery.md",
@@ -1196,7 +1196,7 @@
"ui/storybook/fixtures/paperclipData.ts",
"ui/storybook/stories/tasks/assigned-backlog-safeguards.stories.tsx"
],
"fingerprint": "c605c2eac926e4d0765a6289c22ebba5901de3d536b347f20a8cd293fc9142bc",
"fingerprint": "cdb63642517b31c68df9ca8d62e60039f9f4d69d95d1a96dc96235fb7db1487d",
"stableId": "paperclip-assigned-backlog-safeguards",
"sidebarTitle": "Tasks and conversations/Task creation and lifecycle/Paperclip/Assigned Backlog Safeguards"
},
@@ -1210,8 +1210,8 @@
"status": "unreviewed",
"implementation": "production",
"boundary": "fixtures",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed.",
"reviewedAt": "2026-10-12",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Creation visibility now defaults to hiding automated independent tasks, with a show agent-created tasks control and inbox participation exceptions. Source alignment reviewed; these fixture stories do not establish live server pagination or authorization. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work.",
"reviewedAt": "2026-10-13",
"sources": [
"maps/feature-map/inbox-search.md",
"maps/feature-map/recovery.md",
@@ -1220,7 +1220,7 @@
"ui/storybook/fixtures/paperclipData.ts",
"ui/storybook/stories/inbox-search/blocked-inbox.stories.tsx"
],
"fingerprint": "b6f5f4b7c00e48da7320bef20e5904527f83665e5fdac4fbb44c866e15547502",
"fingerprint": "bcb6c0a3cb34fcd06e7b056521ad84fb968f73ba46a7ba00eda2a86bb060b11b",
"stableId": "product-inbox-blocked-tab",
"sidebarTitle": "Tasks and conversations/Inbox, decisions, and search/Product/Inbox/Blocked tab"
},
@@ -1234,7 +1234,7 @@
"status": "unreviewed",
"implementation": "production",
"boundary": "fixtures",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Task-workspace reconciliation reviewed the expanded workspace recipe; these examples do not establish durable task-folder continuity, repository authorization or sandbox admission. The workspace recipe now requires child boundary, safe reopen and checkpoint ancestry controls; these backend checks are not established by this fixture. The provisioning recipe requires controller script denial for remote selections and copy-only local source choices, including retained denial through metadata changes and reopening; these fixtures do not verify execution placement. Canonical default provisioning follows configured policy, primary, creation time and ID; these fixtures do not run source hooks or establish this backend precedence. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts.",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Task-workspace reconciliation reviewed the expanded workspace recipe; these examples do not establish durable task-folder continuity, repository authorization or sandbox admission. The workspace recipe now requires child boundary, safe reopen and checkpoint ancestry controls; these backend checks are not established by this fixture. The provisioning recipe requires controller script denial for remote selections and copy-only local source choices, including retained denial through metadata changes and reopening; these fixtures do not verify execution placement. Canonical default provisioning follows configured policy, primary, creation time and ID; these fixtures do not run source hooks or establish this backend precedence. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work.",
"reviewedAt": "2026-10-13",
"sources": [
"maps/feature-map/tasks.md",
@@ -1245,7 +1245,7 @@
"ui/storybook/fixtures/browser-use.tsx",
"ui/storybook/stories/workspaces/browser-use-activity.stories.tsx"
],
"fingerprint": "80aa360434184867ea46f1e508d3e97c29a6958f991c40c1866e10e5c16af1b1",
"fingerprint": "f0e77b99e99a69532f45d58546a2324893543911771e850a47ca3452818bcf3d",
"stableId": "tasks-browser-use-task-activity",
"sidebarTitle": "Projects and execution/Workspaces, services, and files/Tasks/Browser Use/Task activity"
},
@@ -1259,7 +1259,7 @@
"status": "unreviewed",
"implementation": "production",
"boundary": "fixtures",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Task-workspace reconciliation reviewed the expanded workspace recipe; these examples do not establish durable task-folder continuity, repository authorization or sandbox admission. The workspace recipe now requires child boundary, safe reopen and checkpoint ancestry controls; these backend checks are not established by this fixture. The provisioning recipe requires controller script denial for remote selections and copy-only local source choices, including retained denial through metadata changes and reopening; these fixtures do not verify execution placement. Canonical default provisioning follows configured policy, primary, creation time and ID; these fixtures do not run source hooks or establish this backend precedence. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts.",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Task-workspace reconciliation reviewed the expanded workspace recipe; these examples do not establish durable task-folder continuity, repository authorization or sandbox admission. The workspace recipe now requires child boundary, safe reopen and checkpoint ancestry controls; these backend checks are not established by this fixture. The provisioning recipe requires controller script denial for remote selections and copy-only local source choices, including retained denial through metadata changes and reopening; these fixtures do not verify execution placement. Canonical default provisioning follows configured policy, primary, creation time and ID; these fixtures do not run source hooks or establish this backend precedence. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work.",
"reviewedAt": "2026-10-13",
"sources": [
"maps/feature-map/tasks.md",
@@ -1269,7 +1269,7 @@
"ui/storybook/fixtures/browser-use.tsx",
"ui/storybook/stories/workspaces/browser-use-footer.stories.tsx"
],
"fingerprint": "ba83c5b16100c735177b19029c587dcd79de2ab537bcaee130326058963bb2dd",
"fingerprint": "b60b13c6ff934b038616eee7da6aeeaac0f595aeb7c8d80d2a2f787c7bb0dbac",
"stableId": "tasks-browser-use-footer",
"sidebarTitle": "Projects and execution/Workspaces, services, and files/Tasks/Browser Use/Footer"
},
@@ -1305,7 +1305,7 @@
"status": "unreviewed",
"implementation": "production",
"boundary": "fixtures",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Task-workspace reconciliation reviewed the expanded workspace recipe; these examples do not establish durable task-folder continuity, repository authorization or sandbox admission. The workspace recipe now requires child boundary, safe reopen and checkpoint ancestry controls; these backend checks are not established by this fixture. The provisioning recipe requires controller script denial for remote selections and copy-only local source choices, including retained denial through metadata changes and reopening; these fixtures do not verify execution placement. Canonical default provisioning follows configured policy, primary, creation time and ID; these fixtures do not run source hooks or establish this backend precedence. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts.",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Task-workspace reconciliation reviewed the expanded workspace recipe; these examples do not establish durable task-folder continuity, repository authorization or sandbox admission. The workspace recipe now requires child boundary, safe reopen and checkpoint ancestry controls; these backend checks are not established by this fixture. The provisioning recipe requires controller script denial for remote selections and copy-only local source choices, including retained denial through metadata changes and reopening; these fixtures do not verify execution placement. Canonical default provisioning follows configured policy, primary, creation time and ID; these fixtures do not run source hooks or establish this backend precedence. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work.",
"reviewedAt": "2026-10-13",
"sources": [
"maps/feature-map/tasks.md",
@@ -1316,7 +1316,7 @@
"ui/storybook/fixtures/paperclipData.ts",
"ui/storybook/stories/workspaces/browser-use.stories.tsx"
],
"fingerprint": "42889268f5e8c23c9ac252a8eddb6b839f05a47594484122a41941c6da7636d0",
"fingerprint": "7dea88462587a256933271c48cfef7ff339f55acd1f77a38bf89ad537c63f3ae",
"stableId": "tasks-browser-use-panel",
"sidebarTitle": "Projects and execution/Workspaces, services, and files/Tasks/Browser Use/Panel"
},
@@ -1387,7 +1387,7 @@
"status": "unreviewed",
"implementation": "production",
"boundary": "fixtures",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Master reconciliation inspected assignment-history recipient suggestions and manual-selection retention; existing stories do not establish the new assignment-history behavior. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts.",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Master reconciliation inspected assignment-history recipient suggestions and manual-selection retention; existing stories do not establish the new assignment-history behavior. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work.",
"reviewedAt": "2026-10-13",
"sources": [
"maps/feature-map/runs-adapters.md",
@@ -1401,7 +1401,7 @@
"ui/storybook/fixtures/paperclipData.ts",
"ui/storybook/stories/tasks/chat-comments.stories.tsx"
],
"fingerprint": "9375c8226472f5e94b44c7e5dbe6046d1a01f70e17ead05811d08e6636639d17",
"fingerprint": "af6b855e4223073858c00f3d39b294222d32a7eb4f9c780cb3a1259a4c3edbdb",
"stableId": "product-chat-comments",
"sidebarTitle": "Tasks and conversations/Task creation and lifecycle/Product/Chat & Comments"
},
@@ -1519,7 +1519,7 @@
"status": "current",
"implementation": "production",
"boundary": "fixtures",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts.",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work.",
"reviewedAt": "2026-10-13",
"sources": [
"maps/feature-map/runs-adapters.md",
@@ -1529,7 +1529,7 @@
"ui/storybook/prototypes/completed-activity/CompletedActivityPreview.tsx",
"ui/storybook/stories/tasks/completed-activity.stories.tsx"
],
"fingerprint": "5a7cb4c48683bde333499fce04c3a0b983f444596ed68ab771b15fc910f05f25",
"fingerprint": "d6a288300082825b36c483a4c1e1dda3ca7ecf4ba7bada065d88ad8f2098c869",
"stableId": "tasks-completed-activity-preview",
"sidebarTitle": "Tasks and conversations/Task creation and lifecycle/Tasks/Completed activity preview"
},
@@ -1542,7 +1542,7 @@
"status": "unreviewed",
"implementation": "production",
"boundary": "fixtures",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Master reconciliation inspected assignment-history recipient suggestions and manual-selection retention; existing stories do not establish the new assignment-history behavior. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts.",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Master reconciliation inspected assignment-history recipient suggestions and manual-selection retention; existing stories do not establish the new assignment-history behavior. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work.",
"reviewedAt": "2026-10-13",
"sources": [
"maps/feature-map/tasks.md",
@@ -1552,7 +1552,7 @@
"ui/storybook/prototypes/composer-model-picker/fixtures.ts",
"ui/storybook/stories/tasks/composer-add-menu.stories.tsx"
],
"fingerprint": "e7a0a6c477048bb9410db5fa29552b6045a4a02520c4437ef0062141a677a134",
"fingerprint": "a3d8d5ddf558df4e5118c747bb1c42ef1d43b23202200614a96c7a4c5ab47e91",
"stableId": "composer-add-menu",
"sidebarTitle": "Tasks and conversations/Task creation and lifecycle/Composer/Add menu"
},
@@ -1566,7 +1566,7 @@
"status": "unreviewed",
"implementation": "production",
"boundary": "fixtures",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts.",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work.",
"reviewedAt": "2026-10-13",
"sources": [
"maps/feature-map/runs-adapters.md",
@@ -1579,7 +1579,7 @@
"ui/storybook/prototypes/composer-model-picker/fixtures.ts",
"ui/storybook/stories/tasks/composer-mobile-assignee.stories.tsx"
],
"fingerprint": "5d8ab0bf43155faaf7a3791409cff9d2afc0a382feaac92c50916c9b9c8e9201",
"fingerprint": "62cb4bb214ab3848b9008c2456293027e86bb5bc55bda9c8671a5ea972555ee8",
"stableId": "composer-mobile-assignee-picker",
"sidebarTitle": "Tasks and conversations/Task creation and lifecycle/Composer/Mobile assignee picker"
},
@@ -1593,7 +1593,7 @@
"status": "mixed",
"implementation": "mixed",
"boundary": "fixtures",
"notes": "Most examples use a local picker implementation; live picker examples use ComposerRunSettingsLiveStory. Do not count the whole suite as production parity. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts.",
"notes": "Most examples use a local picker implementation; live picker examples use ComposerRunSettingsLiveStory. Do not count the whole suite as production parity. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work.",
"reviewedAt": "2026-10-13",
"sources": [
"maps/feature-map/runs-adapters.md",
@@ -1607,7 +1607,7 @@
"ui/storybook/prototypes/composer-model-picker/fixtures.ts",
"ui/storybook/stories/tasks/composer-model-picker.stories.tsx"
],
"fingerprint": "28f590da6e27168049fb39edec3b0d3a8344d5afc6921d622f22a3a02677eccd",
"fingerprint": "6fdfb5463f7601772919b8c73e97b2571f5c13bf728390ecffc22a7438d67ce7",
"stableId": "composer-model-and-effort-picker",
"sidebarTitle": "Tasks and conversations/Task creation and lifecycle/Composer/Model and effort picker"
},
@@ -1775,7 +1775,7 @@
"status": "unreviewed",
"implementation": "production",
"boundary": "fixtures",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts.",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work.",
"reviewedAt": "2026-10-13",
"sources": [
"maps/feature-map/activity.md",
@@ -1792,7 +1792,7 @@
"ui/storybook/fixtures/paperclipData.ts",
"ui/storybook/stories/tasks/control-plane-surfaces.stories.tsx"
],
"fingerprint": "76878f4f9b53c94eac1e74fbb50b943b1f5359c3bddd119cc277bc8073bfe52a",
"fingerprint": "ad5842a0179d5b824f4b08170e82ce66fe3929eb93021af3606e7c9dd81ddc12",
"stableId": "product-control-plane-surfaces",
"sidebarTitle": "Tasks and conversations/Task creation and lifecycle/Product/Control Plane Surfaces"
},
@@ -1928,14 +1928,14 @@
"status": "unreviewed",
"implementation": "production",
"boundary": "fixtures",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed.",
"reviewedAt": "2026-10-12",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work.",
"reviewedAt": "2026-10-13",
"sources": [
"maps/feature-map/inbox-search.md",
"ui/src/components/DecisionCard.tsx",
"ui/storybook/stories/inbox-search/decision-card.stories.tsx"
],
"fingerprint": "220a4f037c1dd4a456ac7df75d6ee7fd0d844ff7db3fd30ca1da2fff9477cbc8",
"fingerprint": "172482180fa305e06238da1fa90a277dd1eb109354d8bfeb0b2b833b9aba798d",
"stableId": "decisions-decisioncard",
"sidebarTitle": "Tasks and conversations/Inbox, decisions, and search/Decisions/DecisionCard"
},
@@ -2022,8 +2022,8 @@
"status": "unreviewed",
"implementation": "production",
"boundary": "fixtures",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed.",
"reviewedAt": "2026-10-12",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work.",
"reviewedAt": "2026-10-13",
"sources": [
"maps/feature-map/inbox-search.md",
"ui/src/components/AttentionQueueRow.tsx",
@@ -2031,7 +2031,7 @@
"ui/src/pages/WhatNeedsMe.tsx",
"ui/storybook/stories/inbox-search/decisions-desk.stories.tsx"
],
"fingerprint": "1e49e931cddd7ef77de70f25fc4ee991d3de9d933670ae4412c5d17fad6db0aa",
"fingerprint": "4b39ccddf9d5ed2847fe0bd9f0078b183ffcaeb41b67121410909ef10a73e938",
"stableId": "pages-decisions-desk",
"sidebarTitle": "Tasks and conversations/Inbox, decisions, and search/Pages/Decisions Desk"
},
@@ -2067,7 +2067,7 @@
"status": "unreviewed",
"implementation": "production",
"boundary": "fixtures",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts.",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work.",
"reviewedAt": "2026-10-13",
"sources": [
"maps/feature-map/agents.md",
@@ -2085,7 +2085,7 @@
"ui/storybook/fixtures/paperclipData.ts",
"ui/storybook/stories/tasks/dialogs-modals.stories.tsx"
],
"fingerprint": "75e4b0effdb3cd0c426dce00f908ca4657a03e2ffc365558d074858020ac5f23",
"fingerprint": "0106caca8a9ad499602499ab64ad96f7cbb9db6815195218775cc317ba7204ad",
"stableId": "product-dialogs-modals",
"sidebarTitle": "Tasks and conversations/Task creation and lifecycle/Product/Dialogs & Modals"
},
@@ -2303,7 +2303,7 @@
"status": "unreviewed",
"implementation": "production",
"boundary": "fixtures",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts.",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Creation visibility now defaults to hiding automated independent tasks, with a show agent-created tasks control and inbox participation exceptions. Source alignment reviewed; these fixture stories do not establish live server pagination or authorization. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work.",
"reviewedAt": "2026-10-13",
"sources": [
"maps/feature-map/tasks.md",
@@ -2318,7 +2318,7 @@
"ui/storybook/fixtures/paperclipData.ts",
"ui/storybook/stories/tasks/external-objects.stories.tsx"
],
"fingerprint": "5484a9480224ce2e2fdc7376e582d26e6d049e6308a1705e45615594cc7db56a",
"fingerprint": "1a7a6fc735b582b7f0968b97d0159528834a499f6d090c0ec678a1092dc6e3ac",
"stableId": "foundations-external-objects",
"sidebarTitle": "Tasks and conversations/Task creation and lifecycle/External Objects"
},
@@ -2883,7 +2883,7 @@
"status": "unreviewed",
"implementation": "production",
"boundary": "fixtures",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts.",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Creation visibility now defaults to hiding automated independent tasks, with a show agent-created tasks control and inbox participation exceptions. Source alignment reviewed; these fixture stories do not establish live server pagination or authorization. Focused creation-visibility stories mount the production collection with simulated hierarchy reads and assert hidden roots, opt-in inclusion, and the unchecked filter control. Creation visibility examples and fixture setup now live in a support module so the surface matrix stays below 1000 lines; exported story IDs are unchanged. Creation visibility now shares the subscribed preference across modern and legacy controls; hierarchy child reads share a bounded rendering budget. Source alignment inspected; server behavior is tested separately. Hierarchy fetch and rendering budgets are separate; loaded context remains during paging. The large-tree UI regression exercises delayed reads in both list interfaces. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work.",
"reviewedAt": "2026-10-13",
"sources": [
"maps/feature-map/tasks.md",
@@ -2902,9 +2902,10 @@
"ui/src/components/PriorityIcon.tsx",
"ui/src/components/StatusBadge.tsx",
"ui/storybook/fixtures/paperclipData.ts",
"ui/storybook/stories/tasks/issue-management.stories.tsx"
"ui/storybook/stories/tasks/issue-management.stories.tsx",
"ui/storybook/support/issue-creation-visibility.tsx"
],
"fingerprint": "1c8ff1f940a366fabec4f2cb3f5bbf84e8d21be64bb301da65dcc39ca24c9faa",
"fingerprint": "554a97d096cb27b9418fa2dc5a3bc0cb853e8bafa128ef9abd7cf1c3df3a6bd5",
"stableId": "product-issue-management",
"sidebarTitle": "Tasks and conversations/Task creation and lifecycle/Product/Issue Management"
},
@@ -3050,7 +3051,7 @@
"status": "unreviewed",
"implementation": "production",
"boundary": "fixtures",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts.",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work.",
"reviewedAt": "2026-10-13",
"sources": [
"maps/feature-map/tasks.md",
@@ -3058,7 +3059,7 @@
"ui/src/components/SearchableSelect.tsx",
"ui/storybook/stories/tasks/mobile-entity-pickers.stories.tsx"
],
"fingerprint": "3707254c9f397fa663d1d51b0af5dbf1a811f34d9d4faf2dea5041116b92f1c8",
"fingerprint": "249524a570189f2b01ef83136346a0d1ee099e233e357aa92ffaecd52a376b32",
"stableId": "components-entity-pickers-mobile",
"sidebarTitle": "Tasks and conversations/Task creation and lifecycle/Components/Entity pickers/Mobile"
},
@@ -3226,7 +3227,7 @@
"status": "current",
"implementation": "production",
"boundary": "fixtures",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. WorktreePicker, ReuseWorktree, CreateWithReusedWorktree and NewWorktreeAfterReuse exercise workspace selection and submitted fixture request values. Actual admission/binding and execution remain outside this story.",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. WorktreePicker, ReuseWorktree, CreateWithReusedWorktree and NewWorktreeAfterReuse exercise workspace selection and submitted fixture request values. Actual admission/binding and execution remain outside this story. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work.",
"reviewedAt": "2026-10-13",
"sources": [
"maps/feature-map/tasks.md",
@@ -3236,7 +3237,7 @@
"ui/storybook/stories/tasks/new-task-composer.stories.tsx",
"maps/feature-map/workspaces.md"
],
"fingerprint": "56ef4e67f8e6b51ab54a664336fae33a75aece2f56883861ce617d53145b5637",
"fingerprint": "db3b18dcf012cfd2174900456dd8f8189b2f0b4287d84fbb62562bb0325a0001",
"stableId": "composer-new-task",
"sidebarTitle": "Tasks and conversations/Task creation and lifecycle/Composer/New task"
},
@@ -3344,7 +3345,7 @@
"status": "unreviewed",
"implementation": "production",
"boundary": "fixtures",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Master reconciliation inspected assignment-history recipient suggestions and manual-selection retention; existing stories do not establish the new assignment-history behavior.",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Master reconciliation inspected assignment-history recipient suggestions and manual-selection retention; existing stories do not establish the new assignment-history behavior. Creation visibility now defaults to hiding automated independent tasks, with a Show agent-created tasks control and inbox participation exceptions. Source alignment reviewed; these fixture stories do not establish live server pagination or authorization.",
"reviewedAt": "2026-10-13",
"sources": [
"maps/feature-map/projects.md",
@@ -3357,7 +3358,7 @@
"ui/storybook/prototypes/originating-tasks/OriginatingTasks.tsx",
"ui/storybook/stories/task-coordination/originating-tasks.stories.tsx"
],
"fingerprint": "2c1e0da025ec60281b4c8179180114d7eee259cf30a1d7216a21bbf476eb7228",
"fingerprint": "59123e73a0286fd11a48376ee152a974d730c59bd5421fd273cfca3a185f6e08",
"stableId": "ux-labs-tasks-created-from-a-task",
"sidebarTitle": "Tasks and conversations/Delegation, dependencies, and signoff/UX Labs/Tasks Created From a Task"
},
@@ -3378,7 +3379,7 @@
"ui/storybook/generated/feature-index.json"
],
"exception": "Shared foundations or contributor guide; no single business capability owns this suite.",
"fingerprint": "b4a1cb9cf763e78cfc632a5adf859c8827318de12eeb0cd359b4a5b8b838a730",
"fingerprint": "408bb736ebe6591fb5a397db6d8b3d3d0b37741a66ed2a7edc84781c67d5c6c7",
"stableId": "overview-storybook-guide",
"sidebarTitle": "Overview/Storybook Guide"
},
@@ -3460,7 +3461,7 @@
"status": "unreviewed",
"implementation": "guide",
"boundary": "static",
"notes": "Review guide retained; explanatory content does not establish runtime or production coverage. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Primary choice, replacement confirmation, unavailable states and task/chat fallback presentation use local presentation-provider callbacks. Production preference persistence and default-resolution precedence remain unverified by this suite.",
"notes": "Review guide retained; explanatory content does not establish runtime or production coverage. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Primary choice, replacement confirmation, unavailable states and task/chat fallback presentation use local presentation-provider callbacks. Production preference persistence and default-resolution precedence remain unverified by this suite. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work.",
"reviewedAt": "2026-10-13",
"sources": [
"maps/feature-map/agent-chat.md",
@@ -3468,7 +3469,7 @@
"maps/feature-map/tasks.md",
"ui/storybook/stories/agents/primary-agent/00-review-guide.stories.tsx"
],
"fingerprint": "d54242a3d8d8096014dd54fe49ca0e86669894ff859d41ff0e50866315a412f4",
"fingerprint": "dc2d1c8a114ba4e6c065170fe2cd6b39c8b6b7dce3d7ae1afbfbddc15adf5beb",
"stableId": "primary-agent-00-review-guide",
"sidebarTitle": "Agents and reusable capabilities/Hiring, configuration, and organization/Primary Agent/00 Review guide"
},
@@ -3483,7 +3484,7 @@
"status": "unreviewed",
"implementation": "production",
"boundary": "fixtures",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Primary choice, replacement confirmation, unavailable states and task/chat fallback presentation use local presentation-provider callbacks. Production preference persistence and default-resolution precedence remain unverified by this suite.",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Primary choice, replacement confirmation, unavailable states and task/chat fallback presentation use local presentation-provider callbacks. Production preference persistence and default-resolution precedence remain unverified by this suite. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work.",
"reviewedAt": "2026-10-13",
"sources": [
"maps/feature-map/agent-chat.md",
@@ -3503,7 +3504,7 @@
"ui/storybook/stories/agents/primary-agent/01-components.stories.tsx",
"ui/storybook/support/primary-agent/PrimaryAgentStory.tsx"
],
"fingerprint": "b1ae1d45a7e4a89f94a4a10343ddabd085cc758f0ceb17df43806722df874019",
"fingerprint": "1ba218400f92d323d120ad223d92a0ddeee6d104ee36f1873e110a3e0124a1bb",
"stableId": "primary-agent-01-components",
"sidebarTitle": "Agents and reusable capabilities/Hiring, configuration, and organization/Primary Agent/01 Components"
},
@@ -3518,7 +3519,7 @@
"status": "unreviewed",
"implementation": "production",
"boundary": "fixtures",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Primary choice, replacement confirmation, unavailable states and task/chat fallback presentation use local presentation-provider callbacks. Production preference persistence and default-resolution precedence remain unverified by this suite.",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Primary choice, replacement confirmation, unavailable states and task/chat fallback presentation use local presentation-provider callbacks. Production preference persistence and default-resolution precedence remain unverified by this suite. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work.",
"reviewedAt": "2026-10-13",
"sources": [
"maps/feature-map/agent-chat.md",
@@ -3537,7 +3538,7 @@
"ui/storybook/stories/agents/primary-agent/02-sidebar.stories.tsx",
"ui/storybook/support/primary-agent/PrimaryAgentStory.tsx"
],
"fingerprint": "a98ea7e6c56135bd030b43385bfdb2a5e12f5e78d18ed301c88ff12da07481a3",
"fingerprint": "cf72eaff02b96c8f81a285c96246ef80e9d97e836b47f8bb88734175d5d01664",
"stableId": "primary-agent-02-sidebar",
"sidebarTitle": "Agents and reusable capabilities/Hiring, configuration, and organization/Primary Agent/02 Sidebar"
},
@@ -3552,7 +3553,7 @@
"status": "unreviewed",
"implementation": "production",
"boundary": "fixtures",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Primary choice, replacement confirmation, unavailable states and task/chat fallback presentation use local presentation-provider callbacks. Production preference persistence and default-resolution precedence remain unverified by this suite.",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Primary choice, replacement confirmation, unavailable states and task/chat fallback presentation use local presentation-provider callbacks. Production preference persistence and default-resolution precedence remain unverified by this suite. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work.",
"reviewedAt": "2026-10-13",
"sources": [
"maps/feature-map/agent-chat.md",
@@ -3571,7 +3572,7 @@
"ui/storybook/stories/agents/primary-agent/03-agents.stories.tsx",
"ui/storybook/support/primary-agent/PrimaryAgentStory.tsx"
],
"fingerprint": "2096810ef9ccf52eaf2811175604550302b314fc2e3d6bb951413a5505c3214b",
"fingerprint": "d8107859209157fdcd775b1e0161aa9b39fd79280b57d2bcd29e76afa1944c2a",
"stableId": "primary-agent-03-agents",
"sidebarTitle": "Agents and reusable capabilities/Hiring, configuration, and organization/Primary Agent/03 Agents"
},
@@ -3586,7 +3587,7 @@
"status": "unreviewed",
"implementation": "production",
"boundary": "fixtures",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Primary choice, replacement confirmation, unavailable states and task/chat fallback presentation use local presentation-provider callbacks. Production preference persistence and default-resolution precedence remain unverified by this suite.",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Primary choice, replacement confirmation, unavailable states and task/chat fallback presentation use local presentation-provider callbacks. Production preference persistence and default-resolution precedence remain unverified by this suite. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work.",
"reviewedAt": "2026-10-13",
"sources": [
"maps/feature-map/agent-chat.md",
@@ -3605,7 +3606,7 @@
"ui/storybook/stories/agents/primary-agent/04-new-task.stories.tsx",
"ui/storybook/support/primary-agent/PrimaryAgentStory.tsx"
],
"fingerprint": "2ab88c703c7376edd519dc413a562ab802998ae25cafc44925fdd00f48ceb7cb",
"fingerprint": "2e30847e4f8d957c11600f3663358e0eb555f2185cb85c4c1c1b4d57eba62f51",
"stableId": "primary-agent-04-new-task",
"sidebarTitle": "Agents and reusable capabilities/Hiring, configuration, and organization/Primary Agent/04 New task"
},
@@ -3620,7 +3621,7 @@
"status": "unreviewed",
"implementation": "production",
"boundary": "fixtures",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Primary choice, replacement confirmation, unavailable states and task/chat fallback presentation use local presentation-provider callbacks. Production preference persistence and default-resolution precedence remain unverified by this suite.",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Primary choice, replacement confirmation, unavailable states and task/chat fallback presentation use local presentation-provider callbacks. Production preference persistence and default-resolution precedence remain unverified by this suite. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work.",
"reviewedAt": "2026-10-13",
"sources": [
"maps/feature-map/agent-chat.md",
@@ -3639,7 +3640,7 @@
"ui/storybook/stories/agents/primary-agent/05-chat.stories.tsx",
"ui/storybook/support/primary-agent/PrimaryAgentStory.tsx"
],
"fingerprint": "2b22fe59288fb0d6597f7122ac195038f3ed8d748c2ed80fba7e795576501cd3",
"fingerprint": "fa3248cdb686fb0827390fbabea3c2ed38950e5234141254a53756cd271b4903",
"stableId": "primary-agent-05-chat",
"sidebarTitle": "Agents and reusable capabilities/Hiring, configuration, and organization/Primary Agent/05 Chat"
},
@@ -3654,7 +3655,7 @@
"status": "unreviewed",
"implementation": "production",
"boundary": "fixtures",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Primary choice, replacement confirmation, unavailable states and task/chat fallback presentation use local presentation-provider callbacks. Production preference persistence and default-resolution precedence remain unverified by this suite.",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Primary choice, replacement confirmation, unavailable states and task/chat fallback presentation use local presentation-provider callbacks. Production preference persistence and default-resolution precedence remain unverified by this suite. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work.",
"reviewedAt": "2026-10-13",
"sources": [
"maps/feature-map/agent-chat.md",
@@ -3673,7 +3674,7 @@
"ui/storybook/stories/agents/primary-agent/06-journeys.stories.tsx",
"ui/storybook/support/primary-agent/PrimaryAgentStory.tsx"
],
"fingerprint": "67c35f4ec63e84d1ccaa4362e2e2289857ecfa583d412c8582168d169ca38a54",
"fingerprint": "68a196913fd72374066dcccf55430d742881a983be2d914de2e02fd98a825fd0",
"stableId": "primary-agent-06-journeys",
"sidebarTitle": "Agents and reusable capabilities/Hiring, configuration, and organization/Primary Agent/06 Journeys"
},
@@ -3688,7 +3689,7 @@
"status": "unreviewed",
"implementation": "production",
"boundary": "fixtures",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Primary choice, replacement confirmation, unavailable states and task/chat fallback presentation use local presentation-provider callbacks. Production preference persistence and default-resolution precedence remain unverified by this suite.",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Primary choice, replacement confirmation, unavailable states and task/chat fallback presentation use local presentation-provider callbacks. Production preference persistence and default-resolution precedence remain unverified by this suite. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work.",
"reviewedAt": "2026-10-13",
"sources": [
"maps/feature-map/agent-chat.md",
@@ -3707,7 +3708,7 @@
"ui/storybook/stories/agents/primary-agent/07-confirmation.stories.tsx",
"ui/storybook/support/primary-agent/PrimaryAgentStory.tsx"
],
"fingerprint": "6be424a8d962be786c09ef1d2c3b505e407c7b645367adabfc2f737d73c692c6",
"fingerprint": "0d65a5877c6ef741b40ddd938c8066608307879ed029baafe59e7248e482558b",
"stableId": "primary-agent-07-confirmation",
"sidebarTitle": "Agents and reusable capabilities/Hiring, configuration, and organization/Primary Agent/07 Confirmation"
},
@@ -3753,14 +3754,14 @@
"status": "unreviewed",
"implementation": "guide",
"boundary": "static",
"notes": "Review guide retained; explanatory content does not establish runtime or production coverage. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts.",
"notes": "Review guide retained; explanatory content does not establish runtime or production coverage. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work.",
"reviewedAt": "2026-10-13",
"sources": [
"maps/feature-map/access.md",
"maps/feature-map/tasks.md",
"ui/storybook/stories/access/private-tasks/00-review-guide.stories.tsx"
],
"fingerprint": "ac5d14d14aa3eec4795ff687b25d1c4025abaa29bb890d45086f1e088b62232d",
"fingerprint": "dc46ad819f4c0d925acbd1170d8a9ee4018f2b49de0241a3b3d698f154ee9257",
"stableId": "private-tasks-00-review-guide",
"sidebarTitle": "Getting started and access/Login, invitations, and access/Private tasks/00 Review guide"
},
@@ -3774,7 +3775,7 @@
"status": "unreviewed",
"implementation": "production",
"boundary": "fixtures",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Master reconciliation inspected assignment-history recipient suggestions and manual-selection retention; existing stories do not establish the new assignment-history behavior. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts.",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Master reconciliation inspected assignment-history recipient suggestions and manual-selection retention; existing stories do not establish the new assignment-history behavior. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Creation visibility now defaults to hiding automated independent tasks, with a show agent-created tasks control and inbox participation exceptions. Source alignment reviewed; these fixture stories do not establish live server pagination or authorization. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work.",
"reviewedAt": "2026-10-13",
"sources": [
"maps/feature-map/access.md",
@@ -3792,7 +3793,7 @@
"ui/storybook/stories/access/private-tasks/06-full-product-pages.stories.tsx",
"ui/storybook/support/private-tasks/PrivacyStory.tsx"
],
"fingerprint": "8010910a61b5f20de41ead806ef1da41c09903b61d47db038fe31c2142960a1e",
"fingerprint": "d4b5ba6bce33a9657d859d3278b1f84bbc9b77cffd24e370214a0fce24c0a02b",
"stableId": "private-tasks-01-creation",
"sidebarTitle": "Getting started and access/Login, invitations, and access/Private tasks/01 Creation"
},
@@ -3806,7 +3807,7 @@
"status": "unreviewed",
"implementation": "production",
"boundary": "fixtures",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts.",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work.",
"reviewedAt": "2026-10-13",
"sources": [
"maps/feature-map/access.md",
@@ -3818,7 +3819,7 @@
"ui/storybook/stories/access/private-tasks/02-sharing.stories.tsx",
"ui/storybook/support/private-tasks/PrivacyStory.tsx"
],
"fingerprint": "29ec80e59e9275be25933e1b87b9a49196af7bd946fb0bd9b21edea52ec58663",
"fingerprint": "6595d72c6af25ff292b389d88e8d2019020f4e4a6965cceb2a50b793ec03b882",
"stableId": "private-tasks-02-sharing",
"sidebarTitle": "Getting started and access/Login, invitations, and access/Private tasks/02 Sharing"
},
@@ -3832,7 +3833,7 @@
"status": "unreviewed",
"implementation": "production",
"boundary": "fixtures",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts.",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work.",
"reviewedAt": "2026-10-13",
"sources": [
"maps/feature-map/access.md",
@@ -3844,7 +3845,7 @@
"ui/storybook/stories/access/private-tasks/03-task-actions.stories.tsx",
"ui/storybook/support/private-tasks/PrivacyStory.tsx"
],
"fingerprint": "249e1e9b5b9f4ff6625734ab176fca3fdfe237238303f843403a506e529517a6",
"fingerprint": "be8143e492deda70c9139b7e9f7022ae6b3c3b7603791074c22adb72a54adb79",
"stableId": "private-tasks-03-task-actions",
"sidebarTitle": "Getting started and access/Login, invitations, and access/Private tasks/03 Task actions"
},
@@ -3858,7 +3859,7 @@
"status": "unreviewed",
"implementation": "production",
"boundary": "fixtures",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts.",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work.",
"reviewedAt": "2026-10-13",
"sources": [
"maps/feature-map/access.md",
@@ -3875,7 +3876,7 @@
"ui/storybook/stories/access/private-tasks/04-references-and-blockers.stories.tsx",
"ui/storybook/support/private-tasks/PrivacyStory.tsx"
],
"fingerprint": "cb879fe3240a4d1e17e3198c07091d53af898f23c176bba2fc381e4b9bb41dea",
"fingerprint": "371547c4293f4f7e6e922113a9a6a2631bfe73979343fe70fc158b2e1fd3c5a4",
"stableId": "private-tasks-04-references-and-blockers",
"sidebarTitle": "Getting started and access/Login, invitations, and access/Private tasks/04 References and blockers"
},
@@ -3890,7 +3891,7 @@
"status": "unreviewed",
"implementation": "production",
"boundary": "fixtures",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts.",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work.",
"reviewedAt": "2026-10-13",
"sources": [
"maps/feature-map/access.md",
@@ -3905,7 +3906,7 @@
"ui/storybook/stories/access/private-tasks/05-projects.stories.tsx",
"ui/storybook/support/private-tasks/PrivacyStory.tsx"
],
"fingerprint": "5bbc18f1689862e62cf534729dda878cc5ca9e9d8e19f23286fb19536206d77b",
"fingerprint": "8b773d099d8ae633ab72108c0a4dd8b2c032aac03787ab47cda05426f456fb15",
"stableId": "private-tasks-05-projects",
"sidebarTitle": "Getting started and access/Login, invitations, and access/Private tasks/05 Projects"
},
@@ -3920,7 +3921,7 @@
"status": "unreviewed",
"implementation": "production",
"boundary": "fixtures",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Master reconciliation inspected assignment-history recipient suggestions and manual-selection retention; existing stories do not establish the new assignment-history behavior. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts.",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Master reconciliation inspected assignment-history recipient suggestions and manual-selection retention; existing stories do not establish the new assignment-history behavior. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Creation visibility now defaults to hiding automated independent tasks, with a show agent-created tasks control and inbox participation exceptions. Source alignment reviewed; these fixture stories do not establish live server pagination or authorization. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work.",
"reviewedAt": "2026-10-13",
"sources": [
"maps/feature-map/access.md",
@@ -3938,7 +3939,7 @@
"ui/storybook/stories/access/private-tasks/06-full-product-pages.stories.tsx",
"ui/storybook/support/private-tasks/PrivacyStory.tsx"
],
"fingerprint": "2972bb8615897132cd38835f2a744a5348a53ab746db4749c9ea91877e9e2485",
"fingerprint": "5fb218d88c3b6815839732e4226a27f4b40a2df46c8cbad6709cb665546b4248",
"stableId": "private-tasks-06-full-product-pages",
"sidebarTitle": "Getting started and access/Login, invitations, and access/Private tasks/06 Full product pages"
},
@@ -3952,7 +3953,7 @@
"status": "unreviewed",
"implementation": "production",
"boundary": "fixtures",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Master reconciliation inspected assignment-history recipient suggestions and manual-selection retention; existing stories do not establish the new assignment-history behavior. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts.",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Master reconciliation inspected assignment-history recipient suggestions and manual-selection retention; existing stories do not establish the new assignment-history behavior. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Creation visibility now defaults to hiding automated independent tasks, with a show agent-created tasks control and inbox participation exceptions. Source alignment reviewed; these fixture stories do not establish live server pagination or authorization. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work.",
"reviewedAt": "2026-10-13",
"sources": [
"maps/feature-map/access.md",
@@ -3985,7 +3986,7 @@
"ui/storybook/stories/access/private-tasks/07-user-stories.stories.tsx",
"ui/storybook/support/private-tasks/PrivacyStory.tsx"
],
"fingerprint": "024bd786a1800aed8756e66b876637280c00a51ce3372363aa74e79893a2913d",
"fingerprint": "5fbe5c61f8754bc0c1db1c6a990b9c44bc5d941b7b61de77fac76300e6c42a22",
"stableId": "private-tasks-07-user-stories",
"sidebarTitle": "Getting started and access/Login, invitations, and access/Private tasks/07 User stories"
},
@@ -4667,7 +4668,7 @@
"status": "current",
"implementation": "production",
"boundary": "fixtures",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts.",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work.",
"reviewedAt": "2026-10-13",
"sources": [
"maps/feature-map/runs-adapters.md",
@@ -4682,7 +4683,7 @@
"ui/storybook/prototypes/runner-activity/RunnerActivityPreview.tsx",
"ui/storybook/stories/tasks/runner-activity.stories.tsx"
],
"fingerprint": "2f7782ae1961a4a8f02c7955edf2a44add21eb2fe241d717cd988ff48d0ca485",
"fingerprint": "99a90f98646e1e307ec6255c7f7bd6ce72958ba83f9968f6e0ae3863949b697a",
"stableId": "tasks-runner-activity-preview",
"sidebarTitle": "Tasks and conversations/Task creation and lifecycle/Tasks/Runner activity preview"
},
@@ -4717,8 +4718,8 @@
"status": "unreviewed",
"implementation": "prototype",
"boundary": "fixtures",
"notes": "Local search-page composition mounts production result components; does not establish parity with the production Search route.",
"reviewedAt": "2026-10-12",
"notes": "Local search-page composition mounts production result components; does not establish parity with the production Search route. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work.",
"reviewedAt": "2026-10-13",
"sources": [
"maps/feature-map/inbox-search.md",
"ui/src/components/PageTabBar.tsx",
@@ -4731,7 +4732,7 @@
"ui/storybook/fixtures/paperclipData.ts",
"ui/storybook/stories/inbox-search/search.stories.tsx"
],
"fingerprint": "4ebfe41c086ce2e0ae674263dfa50239a0770e5e6f98c3c24f54955f6cbdd3d2",
"fingerprint": "a6661b568c8bc74f7667aeff4a5da84a05f507dd62679ee9039808e825eeef61",
"stableId": "product-search-command-k",
"sidebarTitle": "Tasks and conversations/Inbox, decisions, and search/Product/Search & Command K"
},
@@ -5087,15 +5088,15 @@
"status": "unreviewed",
"implementation": "production",
"boundary": "fixtures",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed.",
"reviewedAt": "2026-10-12",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Creation visibility now defaults to hiding automated independent tasks, with a Show agent-created tasks control and inbox participation exceptions. Source alignment reviewed; these fixture stories do not establish live server pagination or authorization. Creation visibility now shares the subscribed preference across modern and legacy controls; hierarchy child reads share a bounded rendering budget. Source alignment inspected; server behavior is tested separately. Hierarchy fetch and rendering budgets are separate; loaded context remains during paging. The large-tree UI regression exercises delayed reads in both list interfaces.",
"reviewedAt": "2026-10-13",
"sources": [
"maps/feature-map/task-coordination.md",
"ui/src/components/IssuesList.tsx",
"ui/storybook/fixtures/paperclipData.ts",
"ui/storybook/stories/task-coordination/sub-issues-workflow.stories.tsx"
],
"fingerprint": "f9ebab21b19cd4aed698c7f1b060c8c6e39788f8224b567d86bf0b4841d038b2",
"fingerprint": "4461d14e90da3e93b82826efdddf131ae014c61a040f33cfae1df1368c6ddb2d",
"stableId": "ux-labs-sub-issues-workflow-checklist",
"sidebarTitle": "Tasks and conversations/Delegation, dependencies, and signoff/UX Labs/Sub-issues Workflow Checklist"
},
@@ -5109,7 +5110,7 @@
"status": "unreviewed",
"implementation": "production",
"boundary": "fixtures",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Master reconciliation inspected assignment-history recipient suggestions and manual-selection retention; existing stories do not establish the new assignment-history behavior. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts.",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Master reconciliation inspected assignment-history recipient suggestions and manual-selection retention; existing stories do not establish the new assignment-history behavior. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work.",
"reviewedAt": "2026-10-13",
"sources": [
"maps/feature-map/recovery.md",
@@ -5121,7 +5122,7 @@
"ui/storybook/fixtures/paperclipData.ts",
"ui/storybook/stories/tasks/successful-run-handoff.stories.tsx"
],
"fingerprint": "8cf0d6e52decc045151c65575984520ac882499baddbeb86ca10b42385863398",
"fingerprint": "2a7db108d46f35f37dd9346d2fc039e61dff8c688e09d9ed7b0e777e7f79af0d",
"stableId": "paperclip-successful-run-handoff",
"sidebarTitle": "Tasks and conversations/Task creation and lifecycle/Paperclip/Successful Run Handoff"
},
@@ -5180,7 +5181,7 @@
"status": "unreviewed",
"implementation": "production",
"boundary": "fixtures",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts.",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work.",
"reviewedAt": "2026-10-13",
"sources": [
"maps/feature-map/runs-adapters.md",
@@ -5192,7 +5193,7 @@
"ui/src/components/task-chat/task-chat-model.ts",
"ui/storybook/stories/tasks/task-chat-chain-of-thought.stories.tsx"
],
"fingerprint": "cd4351774fa50e58fda2f249f2870b7aa376b1eb23a25a4e69280501ef0021d7",
"fingerprint": "4747486949d9bca41e7bed36d511eb523651bc1e23ac0427892ff9b47e29cd28",
"stableId": "tasks-task-chat-review-fixes",
"sidebarTitle": "Tasks and conversations/Task creation and lifecycle/Tasks/Task chat review fixes"
},
@@ -5234,7 +5235,7 @@
"status": "unreviewed",
"implementation": "production",
"boundary": "fixtures",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Master reconciliation inspected assignment-history recipient suggestions and manual-selection retention; existing stories do not establish the new assignment-history behavior. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts.",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Master reconciliation inspected assignment-history recipient suggestions and manual-selection retention; existing stories do not establish the new assignment-history behavior. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work.",
"reviewedAt": "2026-10-13",
"sources": [
"maps/feature-map/tasks.md",
@@ -5245,7 +5246,7 @@
"ui/src/components/task-chat/useWindowAutoFollow.ts",
"ui/storybook/stories/tasks/task-chat-mobile-follow.stories.tsx"
],
"fingerprint": "988ca771ff638613760d91ef8151689f3cb4405135906472541915ebff39d165",
"fingerprint": "840c21389fca0bf13a1df0d247a9d63836d8f38f4ca95c04838ca0cf36b881d9",
"stableId": "task-chat-mobile-streaming-follow",
"sidebarTitle": "Tasks and conversations/Task creation and lifecycle/Task chat/Mobile streaming follow"
},
@@ -5258,7 +5259,7 @@
"status": "unreviewed",
"implementation": "production",
"boundary": "fixtures",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts.",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work.",
"reviewedAt": "2026-10-13",
"sources": [
"maps/feature-map/tasks.md",
@@ -5266,7 +5267,7 @@
"ui/src/components/task-chat/task-chat-model.ts",
"ui/storybook/stories/tasks/task-chat-system-notice.stories.tsx"
],
"fingerprint": "07910730b7ef3be833745377575d4abc41a61dd862428b6711031f1ca2f50eeb",
"fingerprint": "1dd5a86762602b618007a3ed83d0500074560bb9168e7f1873aab0aad555deef",
"stableId": "product-task-chat-system-notice",
"sidebarTitle": "Tasks and conversations/Task creation and lifecycle/Product/Task chat/System notice"
},
@@ -5280,7 +5281,7 @@
"status": "unreviewed",
"implementation": "production",
"boundary": "fixtures",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Master reconciliation inspected assignment-history recipient suggestions and manual-selection retention; existing stories do not establish the new assignment-history behavior. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts.",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Master reconciliation inspected assignment-history recipient suggestions and manual-selection retention; existing stories do not establish the new assignment-history behavior. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work.",
"reviewedAt": "2026-10-13",
"sources": [
"maps/feature-map/questions-and-approvals.md",
@@ -5290,7 +5291,7 @@
"ui/storybook/fixtures/unansweredQuestionChat.tsx",
"ui/storybook/stories/questions-and-approvals/task-chat-unanswered-questions.stories.tsx"
],
"fingerprint": "4fbe4667a042a8fcd8f96d7041d207bc115c7d79a8988196bc6bf18ecda456da",
"fingerprint": "2eb8af0c7b2ecf6914c9bf5d1351427309a5a3ce31b90124c82c23dc2b50bf54",
"stableId": "chat-comments-task-chat-unanswered-questions",
"sidebarTitle": "Tasks and conversations/Questions and approvals/Chat & Comments/Task Chat Unanswered Questions"
},
@@ -5303,7 +5304,7 @@
"status": "unreviewed",
"implementation": "production",
"boundary": "fixtures",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts.",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work.",
"reviewedAt": "2026-10-13",
"sources": [
"maps/feature-map/tasks.md",
@@ -5312,7 +5313,7 @@
"ui/src/components/chat/ExternallyConnectedTaskBanner.tsx",
"ui/storybook/stories/tasks/task-context-notices.stories.tsx"
],
"fingerprint": "737d40d84d6a42dda3366e41f9d6a829219e424c6e770d7e6bb59f2b530b2bfe",
"fingerprint": "10f395d8ecba84925abf8d843deb52af64356008bb96a03668f29870ac430bc8",
"stableId": "tasks-context-notices",
"sidebarTitle": "Tasks and conversations/Task creation and lifecycle/Tasks/Context notices"
},
@@ -5414,7 +5415,7 @@
"status": "unreviewed",
"implementation": "guide",
"boundary": "static",
"notes": "Review guide retained; explanatory content does not establish runtime or production coverage. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts.",
"notes": "Review guide retained; explanatory content does not establish runtime or production coverage. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work.",
"reviewedAt": "2026-10-13",
"sources": [
"maps/feature-map/tasks.md",
@@ -5422,7 +5423,7 @@
"ui/storybook/stories/tasks/thread-human-identity/00-evidence.stories.tsx",
"ui/storybook/support/thread-human-identity/fixtures.ts"
],
"fingerprint": "4e6ed831f9d6049b77a6bfa29da2bf60623f33d70a591f64a4f5c15b3fc38e11",
"fingerprint": "cb8b7d0dcdbd27bcaa16d2fcbc86e776b32db875bc6b4de3d752caa5aa9119da",
"stableId": "chat-comments-human-identity-00-review-guide",
"sidebarTitle": "Tasks and conversations/Task creation and lifecycle/Chat & Comments/Human identity/00 Review guide"
},
@@ -5435,7 +5436,7 @@
"status": "unreviewed",
"implementation": "production",
"boundary": "fixtures",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts.",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work.",
"reviewedAt": "2026-10-13",
"sources": [
"maps/feature-map/tasks.md",
@@ -5446,7 +5447,7 @@
"ui/storybook/stories/tasks/thread-human-identity/01-components.stories.tsx",
"ui/storybook/support/thread-human-identity/fixtures.ts"
],
"fingerprint": "ba528b7605db60c2b739862d5f80cbdc1b4379c77587af41dc040fd1015d30f8",
"fingerprint": "d87a48d3be494149116ab8fd366e90c17aa2e23805fb1f0d896464e10ba35b04",
"stableId": "chat-comments-human-identity-01-components",
"sidebarTitle": "Tasks and conversations/Task creation and lifecycle/Chat & Comments/Human identity/01 Components"
},
@@ -5459,7 +5460,7 @@
"status": "unreviewed",
"implementation": "production",
"boundary": "fixtures",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Master reconciliation inspected assignment-history recipient suggestions and manual-selection retention; existing stories do not establish the new assignment-history behavior. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts.",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Master reconciliation inspected assignment-history recipient suggestions and manual-selection retention; existing stories do not establish the new assignment-history behavior. Expanded upstream verification recipes were inspected; the existing fixture scenarios do not prove the added backend handoff, workspace, recovery or authorization contracts. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work.",
"reviewedAt": "2026-10-13",
"sources": [
"maps/feature-map/tasks.md",
@@ -5469,7 +5470,7 @@
"ui/storybook/stories/tasks/thread-human-identity/02-task-journey.stories.tsx",
"ui/storybook/support/thread-human-identity/fixtures.ts"
],
"fingerprint": "462c55f151c3b297851e351615f0f37afb87b93dd32caa6dfbb128289354f130",
"fingerprint": "68b3cca3a5ed9b116b34bd1dde6ca8012c350c2a7c2b60cc928d7e5b30da8694",
"stableId": "chat-comments-human-identity-02-mixed-author-journey",
"sidebarTitle": "Tasks and conversations/Task creation and lifecycle/Chat & Comments/Human identity/02 Mixed-author journey"
},
@@ -5528,8 +5529,8 @@
"status": "unreviewed",
"implementation": "production",
"boundary": "fixtures",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed.",
"reviewedAt": "2026-10-12",
"notes": "Shipped subjects identified through imports and local wrappers; full state, fixture-contract and route parity remain unreviewed. Creation-visibility verification recipes were updated; this story scenario is unchanged and does not prove that journey. The filter uses one lowercase label without helper text. All chat-channel tasks count as bot-created; the focused visibility stories cover human-initiated channel work.",
"reviewedAt": "2026-10-13",
"sources": [
"maps/feature-map/inbox-search.md",
"ui/src/components/AttentionQueueRow.tsx",
@@ -5537,7 +5538,7 @@
"ui/src/components/ToastViewport.tsx",
"ui/storybook/stories/inbox-search/what-needs-me.stories.tsx"
],
"fingerprint": "d8b838185489f6b5009e52d9c2ac3a1fea3b2718211a1ddc393c404a0335a466",
"fingerprint": "0920cb3c4e75ba896955144a41f714a18dc778ec63f7b3abfa7e08b1032c0e94",
"stableId": "pages-decisions",
"sidebarTitle": "Tasks and conversations/Inbox, decisions, and search/Pages/Decisions"
},
+2
View File
@@ -2879,3 +2879,5 @@ export * from "./validators/task-workspace.js";
export { prepareWorkspaceRepositorySchema, type PrepareWorkspaceRepository } from "./validators/workspace-repository.js";
export * from "./fast-response.js";
export { HUMAN_TASK_ORIGIN_KINDS, isAgentCreatedIssue, type IssueCreationSourceFields } from "./issue-creation-source.js";
@@ -0,0 +1,20 @@
import { describe, expect, it } from "vitest";
import { isAgentCreatedIssue } from "./issue-creation-source.js";
describe("task creation source", () => {
it.each(["manual", "onboarding_first_task"])("preserves human-created %s tasks", (originKind) => {
expect(isAgentCreatedIssue({ createdByUserId: "person", originKind })).toBe(false);
});
it.each(["chat_channel", "routine_execution", "stranded_issue_recovery", "task_watchdog", "harness_liveness_escalation", "plugin:workflow:operation", "built_in_agent_bundle", "pipeline_automation"])("classifies %s as automated even with human attribution", (originKind) => {
expect(isAgentCreatedIssue({ createdByUserId: "person", originKind })).toBe(true);
});
it.each([null, "person"])("classifies channel work as automated with creator %s", (createdByUserId) => {
expect(isAgentCreatedIssue({ originKind: "chat_channel", createdByUserId })).toBe(true);
});
it("recognizes agents and creator-less ordinary tasks", () => {
expect(isAgentCreatedIssue({ createdByAgentId: "agent", originKind: "manual" })).toBe(true);
expect(isAgentCreatedIssue({ originKind: "manual" })).toBe(true);
expect(isAgentCreatedIssue({ createdByUserId: "person", createdByAgentId: "agent" })).toBe(true);
expect(isAgentCreatedIssue({ createdByUserId: "person" })).toBe(false);
});
});
@@ -0,0 +1,17 @@
/** Origins that represent a person's ordinary task or onboarding request. */
export const HUMAN_TASK_ORIGIN_KINDS = ["manual", "onboarding_first_task"] as const;
export interface IssueCreationSourceFields {
createdByAgentId?: string | null;
createdByUserId?: string | null;
originKind?: string | null;
}
/** Creation is independent of who is assigned or responsible for execution. */
export function isAgentCreatedIssue(issue: IssueCreationSourceFields): boolean {
return Boolean(issue.createdByAgentId)
|| !issue.createdByUserId
|| !HUMAN_TASK_ORIGIN_KINDS.includes(
(issue.originKind ?? "manual") as typeof HUMAN_TASK_ORIGIN_KINDS[number],
);
}
@@ -0,0 +1,77 @@
import { randomUUID } from "node:crypto";
import request from "supertest";
import { expect, it } from "vitest";
import { activityLog, issueComments, issueReadStates, issues } from "@paperclipai/db";
import { isAgentCreatedIssue } from "@paperclipai/shared";
import { issueRoutes } from "../routes/issues.js";
import { issueService } from "../services/issues.js";
import { describeEmbeddedPostgres, resetCompanyIssueFixtures, routeApp, seedCompanyWithBoardAccess, useEmbeddedPostgres } from "./helpers/route-test-harness.js";
describeEmbeddedPostgres("issue creation visibility", () => {
const ctx = useEmbeddedPostgres("paperclip-creation-visibility-", {
resetEach: async (db) => {
await db.delete(activityLog);
await resetCompanyIssueFixtures(db);
},
});
it("filters ordinary and compact searches before pagination without changing API defaults", async () => {
const { companyId, userId, actor } = await seedCompanyWithBoardAccess(ctx.db, "Creation visibility");
const other = await seedCompanyWithBoardAccess(ctx.db, "Other company");
const rows = [
{ id: randomUUID(), companyId, title: "Visibility human", createdByUserId: userId, originKind: "manual" },
{ id: randomUUID(), companyId, title: "Visibility second human", createdByUserId: userId, originKind: "manual" },
{ id: randomUUID(), companyId, title: "Visibility channel", createdByUserId: userId, originKind: "chat_channel" },
{ id: randomUUID(), companyId, title: "Visibility onboarding", createdByUserId: userId, originKind: "onboarding_first_task" },
{ id: randomUUID(), companyId, title: "Visibility inbound email", originKind: "chat_channel", originId: "email:endpoint:thread" },
{ id: randomUUID(), companyId, title: "Visibility outbound email", originKind: "chat_channel", originId: "email-send:tool-call" },
...["routine_execution", "task_watchdog", "stranded_issue_recovery", "plugin:workflow:task", "harness_liveness_escalation", "manual"].map((originKind) => ({ id: randomUUID(), companyId, title: `Visibility ${originKind}`, originKind, responsibleUserId: userId })),
{ id: randomUUID(), companyId, title: "Visibility manually run routine", createdByUserId: userId, originKind: "routine_execution" },
];
await ctx.db.insert(issues).values([
...rows.map((row, index) => ({ ...row, status: "todo", updatedAt: new Date(2026, 9, 13, 0, index) })),
{ companyId: other.companyId, title: "Visibility other company", createdByUserId: other.userId },
{ companyId, title: "Visibility private task", createdByUserId: other.userId, visibility: "private" },
]);
const app = routeApp(ctx.db, actor, issueRoutes);
const path = `/api/companies/${companyId}/issues`;
const defaults = await request(app).get(`${path}?includeRoutineExecutions=true`).expect(200);
expect(defaults.body).toHaveLength(rows.length);
for (const view of ["", "&view=compact"]) {
const first = await request(app).get(`${path}?includeAgentCreatedTasks=false&q=Visibility&sortField=updated&limit=2${view}`).expect(200);
const second = await request(app).get(`${path}?includeAgentCreatedTasks=false&q=Visibility&sortField=updated&limit=2&offset=2${view}`).expect(200);
expect(first.body).toHaveLength(2);
expect(second.body).toHaveLength(1);
expect([...first.body, ...second.body].every((issue: Parameters<typeof isAgentCreatedIssue>[0]) => !isAgentCreatedIssue(issue))).toBe(true);
}
await request(app).get(`${path}?includeAgentCreatedTasks=invalid`).expect(400);
await request(app).get(`${path}?includeParticipatedTasks=invalid`).expect(400);
await request(app).get(`/api/companies/${other.companyId}/issues?includeAgentCreatedTasks=false`).expect(403);
});
it("preserves participation but excludes routine ownership and read-only activity", async () => {
const { companyId, userId, actor } = await seedCompanyWithBoardAccess(ctx.db, "Inbox participation");
const ids = Object.fromEntries(["scheduled", "commented", "assigned", "manual", "read", "touched", "channelScheduled", "channelCommented", "channelManual"].map((name) => [name, randomUUID()]));
await ctx.db.insert(issues).values(Object.entries(ids).map(([name, id]) => ({
id, companyId, title: `Participation ${name}`, status: "todo", originKind: name.startsWith("channel") ? "chat_channel" : "routine_execution",
responsibleUserId: userId,
assigneeUserId: name === "assigned" ? userId : null,
createdByUserId: name === "manual" || name === "channelManual" ? userId : null,
})));
await ctx.db.insert(issueComments).values([ids.commented!, ids.channelCommented!].map((issueId) => ({ companyId, issueId, authorUserId: userId, body: "I joined this task" })));
await ctx.db.insert(issueReadStates).values({ companyId, issueId: ids.read!, userId, lastReadAt: new Date() });
await ctx.db.insert(activityLog).values([
{ companyId, entityType: "issue", entityId: ids.read!, actorType: "user", actorId: userId, action: "issue.read_marked" },
{ companyId, entityType: "issue", entityId: ids.touched!, actorType: "user", actorId: userId, action: "issue.inbox_touched" },
]);
const app = routeApp(ctx.db, actor, issueRoutes);
const path = `/api/companies/${companyId}/issues`;
const mine = await request(app).get(`${path}?touchedByUserId=me&inboxArchivedByUserId=me&includeRoutineExecutions=true`).expect(200);
const expected = [ids.commented, ids.assigned, ids.manual, ids.touched, ids.channelCommented, ids.channelManual].sort();
expect(mine.body.map((issue: { id: string }) => issue.id).sort()).toEqual(expected);
const discovery = await request(app).get(`${path}?q=Participation&includeAgentCreatedTasks=false&includeParticipatedTasks=true`).expect(200);
expect(discovery.body.map((issue: { id: string }) => issue.id).sort()).toEqual(expected);
const strict = await issueService(ctx.db).list(companyId, { includeAgentCreatedTasks: false });
expect(strict).toEqual([]);
});
});
+16
View File
@@ -8312,6 +8312,20 @@ export function issueRoutes(
const hasPlanDocument = parseOptionalBooleanQuery(
req.query.hasPlanDocument,
);
const includeParticipatedTasks = parseOptionalBooleanQuery(req.query.includeParticipatedTasks);
if (includeParticipatedTasks === null) {
res.status(400).json({ error: "includeParticipatedTasks must be true or false when provided" });
return;
}
if (includeParticipatedTasks && (req.actor.type !== "board" || !req.actor.userId)) {
res.status(403).json({ error: "includeParticipatedTasks requires board authentication" });
return;
}
const includeAgentCreatedTasks = parseOptionalBooleanQuery(req.query.includeAgentCreatedTasks);
if (includeAgentCreatedTasks === null) {
res.status(400).json({ error: "includeAgentCreatedTasks must be true or false when provided" });
return;
}
const includeLiveDescendantSummary = parseOptionalBooleanQuery(
req.query.includeLiveDescendantSummary,
);
@@ -8479,6 +8493,8 @@ export function issueRoutes(
includeBlockedInboxAttention:
req.query.includeBlockedInboxAttention === "true" ||
req.query.includeBlockedInboxAttention === "1",
includeAgentCreatedTasks,
creationVisibilityUserId: includeParticipatedTasks === true && req.actor.type === "board" ? req.actor.userId : undefined,
includeLiveDescendantSummary: includeLiveDescendantSummary === true,
hasPlanDocument,
q: req.query.q as string | undefined,
+25
View File
@@ -1,4 +1,5 @@
import { automaticReadRecoveryCleanupCondition, touchedByUserCondition } from "./issue-participation.js";
import { HUMAN_TASK_ORIGIN_KINDS } from "@paperclipai/shared";
import { resolveProjectDefaultWorkspaceId } from "./project-default-workspace.js";
import { type AuthorizationActor, executionWorkspaceReadSqlCondition, projectReadSqlCondition } from "./authorization.js";
import { assertTaskWorkspaceAccess, assertTaskWorkspaceSourceProjectAccess } from "./task-workspace-source-access.js";
@@ -1834,6 +1835,9 @@ export interface IssueFilters {
originKind?: string;
originKindPrefix?: string;
originId?: string;
includeAgentCreatedTasks?: boolean;
/** Authenticated inbox discovery can retain existing participation. */
creationVisibilityUserId?: string;
includeRoutineExecutions?: boolean;
excludeRoutineExecutions?: boolean;
includePluginOperations?: boolean;
@@ -6197,6 +6201,21 @@ function assertValidAssigneeAgentFilter(
}
}
function humanCreatedIssueCondition() {
return and(
isNull(issues.createdByAgentId),
isNotNull(issues.createdByUserId),
inArray(issues.originKind, [...HUMAN_TASK_ORIGIN_KINDS]),
)!;
}
function creationVisibilityCondition(companyId: string, filters?: IssueFilters) {
if (filters?.includeAgentCreatedTasks !== false) return undefined;
return filters.creationVisibilityUserId
? or(humanCreatedIssueCondition(), touchedByUserCondition(companyId, filters.creationVisibilityUserId))!
: humanCreatedIssueCondition();
}
async function blockedInboxIssueConditions(
dbOrTx: any,
companyId: string,
@@ -6208,6 +6227,8 @@ async function blockedInboxIssueConditions(
notInArray(issues.status, [...BLOCKED_INBOX_TERMINAL_STATUSES]),
];
if (filters?.readCondition) conditions.push(filters.readCondition);
const creationCondition = creationVisibilityCondition(companyId, filters);
if (creationCondition) conditions.push(creationCondition);
const touchedByUserId = filters?.touchedByUserId?.trim() || undefined;
const inboxArchivedByUserId =
filters?.inboxArchivedByUserId?.trim() || undefined;
@@ -7971,6 +7992,8 @@ export function issueService(db: Db) {
}
if (filters?.afterId) conditions.push(gt(issues.id, filters.afterId));
if (filters?.readCondition) conditions.push(filters.readCondition);
const creationCondition = creationVisibilityCondition(companyId, filters);
if (creationCondition) conditions.push(creationCondition);
const assigneeAgentFilter = parseIssueAssigneeAgentFilter(
filters?.assigneeAgentId,
);
@@ -8299,6 +8322,8 @@ export function issueService(db: Db) {
const conditions = [eq(issues.companyId, companyId), visibleIssueCondition()];
if (filters?.readCondition) conditions.push(filters.readCondition);
const creationCondition = creationVisibilityCondition(companyId, filters);
if (creationCondition) conditions.push(creationCondition);
if (!filters?.q?.trim()) {
conditions.push(isNull(issues.conversationAgentId));
if (!filters?.touchedByUserId && !filters?.unreadForUserId && !filters?.inboxArchivedByUserId) {
+5
View File
@@ -102,6 +102,8 @@ export type IssueListFilters = {
originId?: string;
descendantOf?: string;
createdFromIssueId?: string;
includeAgentCreatedTasks?: boolean;
includeParticipatedTasks?: boolean;
includeRoutineExecutions?: boolean;
includeBlockedBy?: boolean;
includeBlockedInboxAttention?: boolean;
@@ -143,6 +145,9 @@ function issueListSearchParams(filters?: IssueListFilters) {
if (filters?.originId) params.set("originId", filters.originId);
if (filters?.descendantOf) params.set("descendantOf", filters.descendantOf);
if (filters?.createdFromIssueId) params.set("createdFromIssueId", filters.createdFromIssueId);
if (filters?.includeParticipatedTasks) params.set("includeParticipatedTasks", "true");
if (filters?.includeAgentCreatedTasks !== undefined)
params.set("includeAgentCreatedTasks", String(filters.includeAgentCreatedTasks));
if (filters?.includeRoutineExecutions)
params.set("includeRoutineExecutions", "true");
if (filters?.includeBlockedBy) params.set("includeBlockedBy", "true");
+5 -2
View File
@@ -76,10 +76,13 @@ export function BlockedInboxView({
error,
refetch,
} = useQuery({
queryKey: [...queryKeys.issues.listBlockedAttention(companyId), "live-descendant-summary"],
queryKey: [...queryKeys.issues.listBlockedAttention(companyId), "live-descendant-summary", issueFilters.showAgentCreatedTasks],
queryFn: () =>
issuesApi.list(companyId, {
attention: "blocked",
includeRoutineExecutions: true,
includeAgentCreatedTasks: issueFilters.showAgentCreatedTasks,
includeParticipatedTasks: true,
includeBlockedInboxAttention: true,
includeBlockedBy: true,
includeLiveDescendantSummary: true,
@@ -98,7 +101,7 @@ export function BlockedInboxView({
filteredRows.map((row) => row.issue),
issueFilters,
currentUserId,
true,
false,
liveIssueIds,
workspaceFilterContext,
).map((issue) => issue.id),
@@ -65,7 +65,7 @@ describe("IssueFiltersPopover", () => {
agents={[{ id: "agent-1", name: "Agent One" }]}
projects={[{ id: "project-1", name: "Project One" }]}
labels={[{ id: "label-1", name: "Bug", color: "#ff0000" }]}
enableRoutineVisibilityFilter
enableAgentCreatedVisibilityFilter
/>,
);
});
@@ -98,7 +98,7 @@ describe("IssueFiltersPopover", () => {
agents={[{ id: "agent-1", name: "Agent One" }]}
projects={[{ id: "project-1", name: "Project One" }]}
labels={[{ id: "label-1", name: "Bug", color: "#ff0000" }]}
enableRoutineVisibilityFilter
enableAgentCreatedVisibilityFilter
/>,
);
});
@@ -108,6 +108,9 @@ describe("IssueFiltersPopover", () => {
// Status section still renders, Priority section is gated off (PAP-411).
expect(popoverContent?.textContent).toContain("Status");
expect(popoverContent?.textContent).not.toContain("Priority");
const creationToggle = Array.from(popoverContent?.querySelectorAll("label") ?? []).find((label) => label.textContent?.includes("show agent-created tasks"));
expect(creationToggle?.textContent).toBe("show agent-created tasks");
expect(creationToggle?.querySelector("input")?.checked).toBe(false);
});
it("searches long option lists while the popover remains the only scroll owner", () => {
+6 -6
View File
@@ -108,7 +108,7 @@ export function IssueFiltersPopover({
labels,
currentUserId,
enableExternalObjectFilters = true,
enableRoutineVisibilityFilter = false,
enableAgentCreatedVisibilityFilter = false,
buttonVariant = "ghost",
iconOnly = false,
creators,
@@ -123,7 +123,7 @@ export function IssueFiltersPopover({
labels?: LabelOption[];
currentUserId?: string | null;
enableExternalObjectFilters?: boolean;
enableRoutineVisibilityFilter?: boolean;
enableAgentCreatedVisibilityFilter?: boolean;
buttonVariant?: "ghost" | "outline";
iconOnly?: boolean;
creators?: CreatorOption[];
@@ -520,13 +520,13 @@ export function IssueFiltersPopover({
/>
<span className="text-sm">Live runs only</span>
</label>
{enableRoutineVisibilityFilter ? (
{enableAgentCreatedVisibilityFilter ? (
<label className="flex cursor-pointer items-center gap-2 rounded-sm px-2 py-1 hover:bg-accent/50">
<Checkbox
checked={state.hideRoutineExecutions}
onCheckedChange={(checked) => onChange({ hideRoutineExecutions: checked === true })}
checked={state.showAgentCreatedTasks}
onCheckedChange={(checked) => onChange({ showAgentCreatedTasks: checked === true })}
/>
<span className="text-sm">Hide routine runs</span>
<span className="text-sm">show agent-created tasks</span>
</label>
) : null}
</div>
+79 -13
View File
@@ -13,6 +13,7 @@ import {
issueAgeSeparatorLabel,
} from "./IssuesList";
import { TooltipProvider } from "@/components/ui/tooltip";
import { useShowAgentCreatedTasks } from "../hooks/useShowAgentCreatedTasks";
import { taskCollectionPreferencesStorageKey } from "../lib/task-collection-preferences";
const companyState = vi.hoisted(() => ({
@@ -24,6 +25,8 @@ const dialogState = vi.hoisted(() => ({
}));
const mockIssuesApi = vi.hoisted(() => ({
get: vi.fn(),
listAll: vi.fn(),
list: vi.fn(),
listLabels: vi.fn(),
}));
@@ -222,7 +225,7 @@ function createIssue(overrides: Partial<Issue> = {}): Issue {
assigneeUserId: null,
responsibleUserId: null,
createdByAgentId: null,
createdByUserId: null,
createdByUserId: "person",
issueNumber: 1,
requestDepth: 0,
billingCode: null,
@@ -354,6 +357,7 @@ describe("IssuesList", () => {
mockInstanceSettingsApi.getExperimental.mockReset();
mockExternalObjectsApi.getIssueSummaries.mockReset();
mockIssuesApi.list.mockResolvedValue([]);
mockIssuesApi.listAll.mockResolvedValue([]);
mockIssuesApi.listLabels.mockResolvedValue([]);
mockAuthApi.getSession.mockResolvedValue({ user: null, session: null });
mockAccessApi.listMembers.mockResolvedValue({ members: [], access: {} });
@@ -1354,7 +1358,7 @@ describe("IssuesList", () => {
agents={[]}
projects={[]}
viewStateKey="paperclip:test-issues"
enableRoutineVisibilityFilter
enableAgentCreatedVisibilityFilter
onUpdateIssue={() => undefined}
/>,
container,
@@ -1365,11 +1369,13 @@ describe("IssuesList", () => {
status: "backlog",
limit: 200,
includeRoutineExecutions: true,
includeAgentCreatedTasks: false,
}), { signal: expect.any(AbortSignal) });
expect(mockIssuesApi.list).toHaveBeenCalledWith("company-1", expect.objectContaining({
status: "done",
limit: 200,
includeRoutineExecutions: true,
includeAgentCreatedTasks: false,
}), { signal: expect.any(AbortSignal) });
expect(mockKanbanBoard).toHaveBeenLastCalledWith(expect.objectContaining({
issues: expect.arrayContaining([
@@ -1561,6 +1567,48 @@ describe("IssuesList", () => {
});
});
it.each([true, false])("retains loaded context while revealing a large automated tree (streamlined=%s)", async (streamlined) => {
mockInstanceSettingsApi.getExperimental.mockResolvedValue({ enableStreamlinedUi: streamlined });
const parent = createIssue({ id: "human-root", createdByUserId: "person", originKind: "manual" });
const children = Array.from({ length: 250 }, (_, index) => createIssue({
id: `automated-child-${index}`, title: `Automated child ${index}`,
parentId: parent.id, createdByUserId: null, createdByAgentId: "agent", originKind: "manual",
}));
let holdNextRead = false;
let releaseRead: (() => void) | undefined;
mockIssuesApi.list.mockImplementation(async (_companyId, filters) => {
if (filters.parentId !== parent.id) return [];
const rows = children.slice(filters.offset ?? 0, (filters.offset ?? 0) + filters.limit);
if (holdNextRead) {
holdNextRead = false;
return new Promise<Issue[]>((resolve) => { releaseRead = () => resolve(rows); });
}
return rows;
});
const { root } = renderWithQueryClient(
<IssuesList issues={[parent]} agents={[]} projects={[]} viewStateKey="paperclip:test-tree"
enableAgentCreatedVisibilityFilter onUpdateIssue={() => undefined} />,
container,
);
await waitForAssertion(() => expect(container.querySelectorAll("[data-testid='issue-row']")).toHaveLength(100));
holdNextRead = true;
act(() => {
setDocumentScrollMetrics({ innerHeight: 600, scrollY: 1500, scrollHeight: 2000 });
window.dispatchEvent(new Event("scroll"));
});
await flushAnimationFrame();
await waitForAssertion(() => {
expect(releaseRead).toBeDefined();
expect(container.querySelectorAll("[data-testid='issue-row']").length).toBeGreaterThanOrEqual(100);
});
await act(async () => releaseRead!());
await waitForAssertion(() => {
expect(container.querySelectorAll("[data-testid='issue-row']")).toHaveLength(251);
expect(container.textContent).toContain("Automated child 249");
}, 60);
act(() => root.unmount());
});
it("keeps rendering local issue batches while the user stays near the bottom", async () => {
const manyIssues = Array.from({ length: 420 }, (_, index) =>
createIssue({
@@ -2014,11 +2062,17 @@ describe("IssuesList", () => {
});
});
it("shows routine-backed issues by default and hides them when the routine filter is toggled off", async () => {
it.each([true, false])("keeps visibility controls and fetching preferences synchronized (streamlined=%s)", async (streamlined) => {
mockInstanceSettingsApi.getExperimental.mockResolvedValue({ enableStreamlinedUi: streamlined });
function PreferenceProbe() {
const included = useShowAgentCreatedTasks("company-1", "paperclip:test-issues");
return <span data-testid="creation-preference">{String(included)}</span>;
}
const manualIssue = createIssue({
id: "issue-manual",
identifier: "PAP-10",
title: "Manual issue",
createdByUserId: "person",
originKind: "manual",
});
const routineIssue = createIssue({
@@ -2029,20 +2083,20 @@ describe("IssuesList", () => {
});
const { root } = renderWithQueryClient(
<IssuesList
<><PreferenceProbe /><IssuesList
issues={[manualIssue, routineIssue]}
agents={[]}
projects={[]}
viewStateKey="paperclip:test-issues"
enableRoutineVisibilityFilter
enableAgentCreatedVisibilityFilter
onUpdateIssue={() => undefined}
/>,
/></>,
container,
);
await waitForAssertion(() => {
expect(container.textContent).toContain("Manual issue");
expect(container.textContent).toContain("Routine issue");
expect(container.textContent).not.toContain("Routine issue");
});
await act(async () => {
@@ -2055,26 +2109,38 @@ describe("IssuesList", () => {
await waitForAssertion(() => {
const toggle = Array.from(document.body.querySelectorAll("label")).find(
(label) => label.textContent?.includes("Hide routine runs"),
(label) => label.textContent?.includes("show agent-created tasks"),
);
expect(toggle).not.toBeUndefined();
});
await act(async () => {
const toggle = Array.from(document.body.querySelectorAll("label")).find(
(label) => label.textContent?.includes("Hide routine runs"),
(label) => label.textContent?.includes("show agent-created tasks"),
);
toggle?.dispatchEvent(new MouseEvent("click", { bubbles: true }));
await Promise.resolve();
});
await waitForAssertion(() => {
expect(container.textContent).toContain("Routine issue");
expect(container.querySelector("[data-testid='creation-preference']")?.textContent).toBe("true");
});
const preferenceKey = taskCollectionPreferencesStorageKey({ companyId: "company-1", collectionKey: "paperclip:test-issues" });
const envelope = JSON.parse(localStorage.getItem(preferenceKey)!);
await act(async () => {
localStorage.setItem(preferenceKey, JSON.stringify({ ...envelope, viewState: { ...envelope.viewState, showAgentCreatedTasks: false } }));
window.dispatchEvent(new StorageEvent("storage", { key: preferenceKey }));
});
await waitForAssertion(() => {
expect(container.textContent).not.toContain("Routine issue");
expect(container.querySelector("[data-testid='creation-preference']")?.textContent).toBe("false");
const label = Array.from(document.body.querySelectorAll("label")).find((element) => element.textContent?.includes("show agent-created tasks"));
const checkbox = label?.querySelector("[role='checkbox'], input[type='checkbox']");
expect(checkbox).not.toBeNull();
expect(checkbox instanceof HTMLInputElement ? checkbox.checked : checkbox?.getAttribute("aria-checked") === "true").toBe(false);
});
act(() => {
root.unmount();
});
act(() => root.unmount());
});
it("blurs the search input on Enter without clearing the query", async () => {
+65 -26
View File
@@ -1,3 +1,6 @@
import { useShowAgentCreatedTasks } from "../hooks/useShowAgentCreatedTasks";
import { useIssueHierarchyContext } from "../hooks/useIssueHierarchyContext";
import { includeIssueHierarchyContext } from "../lib/issue-hierarchy-context";
import { AgentIdentity } from "@/components/AgentIdentity";
import { startTransition, useDeferredValue, useEffect, useMemo, useState, useCallback, useRef } from "react";
import type { ReactNode } from "react";
@@ -495,7 +498,7 @@ interface IssuesListProps {
* tokens + wall-clock runtime for every run in the tree.
*/
parentIssueIdForCostSummary?: string;
enableRoutineVisibilityFilter?: boolean;
enableAgentCreatedVisibilityFilter?: boolean;
hasMoreIssues?: boolean;
isLoadingMoreIssues?: boolean;
mutedIssueIds?: Set<string>;
@@ -735,7 +738,7 @@ function StreamlinedIssuesList({
defaultSortField,
showProgressSummary = false,
parentIssueIdForCostSummary,
enableRoutineVisibilityFilter = false,
enableAgentCreatedVisibilityFilter = false,
hasMoreIssues = false,
isLoadingMoreIssues = false,
mutedIssueIds,
@@ -822,10 +825,17 @@ function StreamlinedIssuesList({
initialStatuses,
),
);
const showAgentCreatedTasks = useShowAgentCreatedTasks(selectedCompanyId, viewStateKey);
useEffect(() => {
if (!enableAgentCreatedVisibilityFilter) return;
setViewState((previous) => previous.showAgentCreatedTasks === showAgentCreatedTasks
? previous : { ...previous, showAgentCreatedTasks });
}, [enableAgentCreatedVisibilityFilter, showAgentCreatedTasks]);
const [assigneePickerIssueId, setAssigneePickerIssueId] = useState<string | null>(null);
const [assigneeSearch, setAssigneeSearch] = useState("");
const [issueSearch, setIssueSearch] = useState(initialSearch ?? "");
const [renderedIssueRowLimit, setRenderedIssueRowLimit] = useState(INITIAL_ISSUE_ROW_RENDER_LIMIT);
const [hierarchyRowBudget, setHierarchyRowBudget] = useState(INITIAL_ISSUE_ROW_RENDER_LIMIT);
const [visibleIssueColumns, setVisibleIssueColumns] = useState<InboxIssueColumn[]>(initialPreferences.columns);
const renderedIssueIdsRef = useRef("");
const initialServerFillRequestedRef = useRef(false);
@@ -895,6 +905,8 @@ function StreamlinedIssuesList({
// Deleted or reassigned issues leave orphan IDs in localStorage; this keeps
// the stored array bounded to only current parent IDs.
useEffect(() => {
// Contextual children are loaded separately from independent results.
if (enableAgentCreatedVisibilityFilter) return;
const parentIds = new Set(issues.map((i) => i.parentId).filter(Boolean) as string[]);
const pruned = viewState.collapsedParents.filter((id) => parentIds.has(id));
if (pruned.length !== viewState.collapsedParents.length) {
@@ -909,7 +921,8 @@ function StreamlinedIssuesList({
searchFilters ?? {},
"compact",
ISSUE_SEARCH_RESULT_LIMIT,
enableRoutineVisibilityFilter ? "with-routine-executions" : "without-routine-executions",
enableAgentCreatedVisibilityFilter ? "with-routine-executions" : "without-routine-executions",
enableAgentCreatedVisibilityFilter ? viewState.showAgentCreatedTasks : undefined,
],
queryFn: ({ signal }) =>
issuesApi.listCompact(selectedCompanyId!, {
@@ -917,7 +930,7 @@ function StreamlinedIssuesList({
projectId,
limit: ISSUE_SEARCH_RESULT_LIMIT,
...searchFilters,
...(enableRoutineVisibilityFilter ? { includeRoutineExecutions: true } : {}),
...(enableAgentCreatedVisibilityFilter ? { includeRoutineExecutions: true, includeAgentCreatedTasks: viewState.showAgentCreatedTasks } : {}),
}, { signal }).then((rows) => rows as Issue[]),
enabled: !!selectedCompanyId && normalizedIssueSearch.length > 0 && !searchWithinLoadedIssues,
placeholderData: (previousData) => previousData,
@@ -933,7 +946,8 @@ function StreamlinedIssuesList({
searchFilters ?? {},
"compact",
ISSUE_BOARD_COLUMN_RESULT_LIMIT,
enableRoutineVisibilityFilter ? "with-routine-executions" : "without-routine-executions",
enableAgentCreatedVisibilityFilter ? "with-routine-executions" : "without-routine-executions",
enableAgentCreatedVisibilityFilter ? viewState.showAgentCreatedTasks : undefined,
],
queryFn: ({ signal }: { signal: AbortSignal }) =>
issuesApi.listCompact(selectedCompanyId!, {
@@ -942,7 +956,7 @@ function StreamlinedIssuesList({
projectId,
status,
limit: ISSUE_BOARD_COLUMN_RESULT_LIMIT,
...(enableRoutineVisibilityFilter ? { includeRoutineExecutions: true } : {}),
...(enableAgentCreatedVisibilityFilter ? { includeRoutineExecutions: true, includeAgentCreatedTasks: viewState.showAgentCreatedTasks } : {}),
}, { signal }).then((rows) => rows as Issue[]),
enabled: !!selectedCompanyId && viewState.viewMode === "board" && !searchWithinLoadedIssues,
placeholderData: (previousData: Issue[] | undefined) => previousData,
@@ -1202,7 +1216,7 @@ function StreamlinedIssuesList({
searchScopedIssues,
viewState,
currentUserId,
enableRoutineVisibilityFilter,
enableAgentCreatedVisibilityFilter,
liveIssueIds,
issueFilterContext,
);
@@ -1211,7 +1225,7 @@ function StreamlinedIssuesList({
searchScopedIssues,
viewState,
currentUserId,
enableRoutineVisibilityFilter,
enableAgentCreatedVisibilityFilter,
liveIssueIds,
issueFilterContext,
]);
@@ -1269,7 +1283,7 @@ function StreamlinedIssuesList({
enabled: !!selectedCompanyId,
});
const activeFilterCount = countActiveIssueFilters(viewState, enableRoutineVisibilityFilter);
const activeFilterCount = countActiveIssueFilters(viewState, enableAgentCreatedVisibilityFilter);
const boardHighVolume = viewState.viewMode === "board" && filtered.length > KANBAN_BOARD_HIGH_VOLUME_THRESHOLD;
const boardCompactCards =
viewState.boardCardDensity === "compact"
@@ -1287,7 +1301,13 @@ function StreamlinedIssuesList({
|| viewState.boardColdLaneMode !== "auto"
|| viewState.boardColumnPageSize !== KANBAN_COLUMN_DEFAULT_PAGE_SIZE;
const groupedContent = useMemo(() => {
const hierarchyEnabled = enableAgentCreatedVisibilityFilter && !viewState.showAgentCreatedTasks && viewState.nestingEnabled && viewState.viewMode === "list";
const hierarchy = useIssueHierarchyContext(
selectedCompanyId, filtered.slice(0, renderedIssueRowLimit), viewState.collapsedParents,
hierarchyEnabled,
hierarchyRowBudget,
);
const baseGroupedContent = useMemo(() => {
if (viewState.groupBy === "none") {
return [{ key: "__all", label: null as string | null, items: filtered }];
}
@@ -1379,6 +1399,14 @@ function StreamlinedIssuesList({
companyUserLabelMap,
projectById,
]);
const groupedContent = useMemo(() => baseGroupedContent.map((group) => ({
...group,
items: enableAgentCreatedVisibilityFilter && !viewState.showAgentCreatedTasks && viewState.nestingEnabled && viewState.viewMode === "list"
? includeIssueHierarchyContext(group.items, [...issues, ...hierarchy.issues])
: group.items,
})), [baseGroupedContent, hierarchy.issues, issues, enableAgentCreatedVisibilityFilter, viewState.showAgentCreatedTasks, viewState.nestingEnabled, viewState.viewMode]);
const visibleListRowCount = groupedContent.reduce((total, group) => total + group.items.length, 0);
// Flattened visible order (group headers, then tree DFS per group —
// collapsed groups keep their header entry but skip their rows) — must
@@ -1568,31 +1596,41 @@ function StreamlinedIssuesList({
const previousIssueIds = renderedIssueIdsRef.current;
renderedIssueIdsRef.current = nextIssueIds;
const sameResultsOrAppend = previousIssueIds.length > 0 && nextIssueIds.startsWith(previousIssueIds);
if (!sameResultsOrAppend) setHierarchyRowBudget(INITIAL_ISSUE_ROW_RENDER_LIMIT);
setRenderedIssueRowLimit((current) => {
const nextInitialLimit = Math.min(filtered.length, INITIAL_ISSUE_ROW_RENDER_LIMIT);
const listAppended = previousIssueIds.length > 0
&& nextIssueIds.startsWith(previousIssueIds)
&& filtered.length >= current;
if (listAppended) return Math.min(filtered.length, Math.max(current, nextInitialLimit));
const nextInitialLimit = Math.min(visibleListRowCount, INITIAL_ISSUE_ROW_RENDER_LIMIT);
// Context arrives asynchronously and must not undo a reveal request.
if (hierarchyEnabled && sameResultsOrAppend) return Math.max(current, nextInitialLimit);
const listAppended = sameResultsOrAppend && visibleListRowCount >= current;
if (listAppended) return Math.min(visibleListRowCount, Math.max(current, nextInitialLimit));
return nextInitialLimit;
});
}, [filtered, viewState.viewMode]);
}, [filtered, visibleListRowCount, viewState.viewMode, hierarchyEnabled]);
const hasMoreRenderedRows = viewState.viewMode === "list" && renderedIssueRowLimit < filtered.length;
const remainingIssueRowCount = Math.max(filtered.length - renderedIssueRowLimit, 0);
const hasMoreHierarchyRows = hierarchyEnabled && hierarchy.hasMore;
const hasMoreRenderedRows = viewState.viewMode === "list" && renderedIssueRowLimit < visibleListRowCount;
const remainingIssueRowCount = Math.max(visibleListRowCount - renderedIssueRowLimit, 0);
const loadMoreIssueRows = useCallback(() => {
if (viewState.viewMode !== "list") return;
if (hasMoreHierarchyRows && !hierarchy.isFetching) {
setHierarchyRowBudget((current) => current + ISSUE_ROW_RENDER_BATCH_SIZE);
setRenderedIssueRowLimit((current) => current + ISSUE_ROW_RENDER_BATCH_SIZE);
return;
}
if (hasMoreRenderedRows) {
setRenderedIssueRowLimit((current) => Math.min(filtered.length, current + ISSUE_ROW_RENDER_BATCH_SIZE));
setRenderedIssueRowLimit((current) => Math.min(visibleListRowCount, current + ISSUE_ROW_RENDER_BATCH_SIZE));
return;
}
if (hasMoreIssues && !isLoadingMoreIssues) {
onLoadMoreIssues?.();
}
}, [
filtered.length,
visibleListRowCount,
hasMoreIssues,
hasMoreRenderedRows,
hasMoreHierarchyRows,
hierarchy.isFetching,
isLoadingMoreIssues,
onLoadMoreIssues,
viewState.viewMode,
@@ -1600,7 +1638,7 @@ function StreamlinedIssuesList({
const canLoadMoreIssues = viewState.viewMode === "list"
&& !isLoading
&& (hasMoreRenderedRows || (hasMoreIssues && !isLoadingMoreIssues));
&& (hasMoreRenderedRows || (hasMoreHierarchyRows && !hierarchy.isFetching) || (hasMoreIssues && !isLoadingMoreIssues));
useEffect(() => {
if (!canLoadMoreIssues) return;
@@ -1911,7 +1949,7 @@ function StreamlinedIssuesList({
labels={labels?.map((label) => ({ id: label.id, name: label.name, color: label.color }))}
currentUserId={currentUserId}
enableExternalObjectFilters={externalObjectsEnabled}
enableRoutineVisibilityFilter={enableRoutineVisibilityFilter}
enableAgentCreatedVisibilityFilter={enableAgentCreatedVisibilityFilter}
iconOnly
presentation={rowPresentation === "task" ? "streamlined" : "legacy"}
/>
@@ -2016,7 +2054,8 @@ function StreamlinedIssuesList({
Some board columns are showing up to {ISSUE_BOARD_COLUMN_RESULT_LIMIT} tasks. Refine filters or search to reveal the rest.
</p>
)}
{!isLoading && !externalObjectFilterLoading && filtered.length === 0 && viewState.viewMode === "list" && (
{hierarchy.error ? <p className="text-sm text-destructive">Failed to load task hierarchy: {hierarchy.error.message}</p> : null}
{!isLoading && !externalObjectFilterLoading && visibleListRowCount === 0 && viewState.viewMode === "list" && (
<EmptyState
icon={CircleDot}
message="No tasks match the current filters or search."
@@ -2513,13 +2552,13 @@ function StreamlinedIssuesList({
</Collapsible>
);
})}
{(remainingIssueRowCount > 0 || hasMoreIssues || isLoadingMoreIssues) && (
{(remainingIssueRowCount > 0 || hasMoreHierarchyRows || hasMoreIssues || isLoadingMoreIssues) && (
<div className="py-2" data-testid="issues-load-more-sentinel">
<p className="text-xs text-muted-foreground">
{isLoadingMoreIssues
{isLoadingMoreIssues || (hierarchyEnabled && hierarchy.isFetching)
? "Loading more tasks..."
: remainingIssueRowCount > 0
? `Rendering ${Math.min(renderedIssueRowLimit, filtered.length)} of ${filtered.length} tasks`
? `Rendering ${Math.min(renderedIssueRowLimit, visibleListRowCount)} of ${visibleListRowCount} tasks`
: "Scroll to load more tasks"}
</p>
</div>
+76 -45
View File
@@ -1,3 +1,7 @@
import { saveTaskCollectionPreferences } from "../lib/task-collection-preferences";
import { useShowAgentCreatedTasks } from "../hooks/useShowAgentCreatedTasks";
import { useIssueHierarchyContext } from "../hooks/useIssueHierarchyContext";
import { includeIssueHierarchyContext } from "../lib/issue-hierarchy-context";
import { AgentIdentity } from "@/components/AgentIdentity";
import { startTransition, useDeferredValue, useEffect, useMemo, useState, useCallback, useRef } from "react";
import type { ReactNode } from "react";
@@ -208,10 +212,6 @@ function getViewState(key: string): IssueViewState {
return { ...defaultViewState };
}
function saveViewState(key: string, state: IssueViewState) {
localStorage.setItem(key, JSON.stringify(state));
}
function getInitialViewState(
key: string,
initialAssignees?: string[],
@@ -269,17 +269,6 @@ function loadIssueColumns(key: string): InboxIssueColumn[] {
}
}
function saveIssueColumns(key: string, columns: InboxIssueColumn[]) {
try {
localStorage.setItem(
getIssueColumnsStorageKey(key),
JSON.stringify(normalizeInboxIssueColumns(columns)),
);
} catch {
// Ignore localStorage failures.
}
}
function sortIssues(issues: Issue[], state: IssueViewState): Issue[] {
if (state.sortField === "workflow") {
const ordered = workflowSort(issues);
@@ -489,7 +478,7 @@ interface IssuesListProps {
* tokens + wall-clock runtime for every run in the tree.
*/
parentIssueIdForCostSummary?: string;
enableRoutineVisibilityFilter?: boolean;
enableAgentCreatedVisibilityFilter?: boolean;
hasMoreIssues?: boolean;
isLoadingMoreIssues?: boolean;
mutedIssueIds?: Set<string>;
@@ -700,7 +689,7 @@ export function IssuesList({
defaultSortField,
showProgressSummary = false,
parentIssueIdForCostSummary,
enableRoutineVisibilityFilter = false,
enableAgentCreatedVisibilityFilter = false,
hasMoreIssues = false,
isLoadingMoreIssues = false,
mutedIssueIds,
@@ -766,10 +755,17 @@ export function IssuesList({
const [viewState, setViewState] = useState<IssueViewState>(() =>
getInitialWorkspaceViewState(scopedKey, initialAssignees, initialWorkspaces, defaultSortField),
);
const showAgentCreatedTasks = useShowAgentCreatedTasks(selectedCompanyId, viewStateKey);
useEffect(() => {
if (!enableAgentCreatedVisibilityFilter) return;
setViewState((previous) => previous.showAgentCreatedTasks === showAgentCreatedTasks
? previous : { ...previous, showAgentCreatedTasks });
}, [enableAgentCreatedVisibilityFilter, showAgentCreatedTasks]);
const [assigneePickerIssueId, setAssigneePickerIssueId] = useState<string | null>(null);
const [assigneeSearch, setAssigneeSearch] = useState("");
const [issueSearch, setIssueSearch] = useState(initialSearch ?? "");
const [renderedIssueRowLimit, setRenderedIssueRowLimit] = useState(INITIAL_ISSUE_ROW_RENDER_LIMIT);
const [hierarchyRowBudget, setHierarchyRowBudget] = useState(INITIAL_ISSUE_ROW_RENDER_LIMIT);
const [visibleIssueColumns, setVisibleIssueColumns] = useState<InboxIssueColumn[]>(() => loadIssueColumns(scopedKey));
const renderedIssueIdsRef = useRef("");
const initialServerFillRequestedRef = useRef(false);
@@ -801,10 +797,13 @@ export function IssuesList({
const updateView = useCallback((patch: Partial<IssueViewState>) => {
setViewState((prev) => {
const next = { ...prev, ...patch };
saveViewState(scopedKey, next);
saveTaskCollectionPreferences({
companyId: selectedCompanyId ?? "__unscoped__", collectionKey: viewStateKey,
legacyViewStorageKey: scopedKey, legacyColumnsStorageKey: getIssueColumnsStorageKey(scopedKey),
}, { viewState: next, columns: visibleIssueColumns });
return next;
});
}, [scopedKey]);
}, [scopedKey, selectedCompanyId, viewStateKey, visibleIssueColumns]);
useEffect(() => {
if (!experimentalSettingsLoaded || externalObjectsEnabled || viewState.externalObjectStatuses.length === 0) return;
@@ -815,6 +814,8 @@ export function IssuesList({
// Deleted or reassigned issues leave orphan IDs in localStorage; this keeps
// the stored array bounded to only current parent IDs.
useEffect(() => {
// Contextual children are loaded separately from independent results.
if (enableAgentCreatedVisibilityFilter) return;
const parentIds = new Set(issues.map((i) => i.parentId).filter(Boolean) as string[]);
const pruned = viewState.collapsedParents.filter((id) => parentIds.has(id));
if (pruned.length !== viewState.collapsedParents.length) {
@@ -829,7 +830,8 @@ export function IssuesList({
searchFilters ?? {},
"compact",
ISSUE_SEARCH_RESULT_LIMIT,
enableRoutineVisibilityFilter ? "with-routine-executions" : "without-routine-executions",
enableAgentCreatedVisibilityFilter ? "with-routine-executions" : "without-routine-executions",
enableAgentCreatedVisibilityFilter ? viewState.showAgentCreatedTasks : undefined,
],
queryFn: ({ signal }) =>
issuesApi.listCompact(selectedCompanyId!, {
@@ -837,7 +839,7 @@ export function IssuesList({
projectId,
limit: ISSUE_SEARCH_RESULT_LIMIT,
...searchFilters,
...(enableRoutineVisibilityFilter ? { includeRoutineExecutions: true } : {}),
...(enableAgentCreatedVisibilityFilter ? { includeRoutineExecutions: true, includeAgentCreatedTasks: viewState.showAgentCreatedTasks } : {}),
}, { signal }).then((rows) => rows as Issue[]),
enabled: !!selectedCompanyId && normalizedIssueSearch.length > 0 && !searchWithinLoadedIssues,
placeholderData: (previousData) => previousData,
@@ -853,7 +855,8 @@ export function IssuesList({
searchFilters ?? {},
"compact",
ISSUE_BOARD_COLUMN_RESULT_LIMIT,
enableRoutineVisibilityFilter ? "with-routine-executions" : "without-routine-executions",
enableAgentCreatedVisibilityFilter ? "with-routine-executions" : "without-routine-executions",
enableAgentCreatedVisibilityFilter ? viewState.showAgentCreatedTasks : undefined,
],
queryFn: ({ signal }: { signal: AbortSignal }) =>
issuesApi.listCompact(selectedCompanyId!, {
@@ -862,7 +865,7 @@ export function IssuesList({
projectId,
status,
limit: ISSUE_BOARD_COLUMN_RESULT_LIMIT,
...(enableRoutineVisibilityFilter ? { includeRoutineExecutions: true } : {}),
...(enableAgentCreatedVisibilityFilter ? { includeRoutineExecutions: true, includeAgentCreatedTasks: viewState.showAgentCreatedTasks } : {}),
}, { signal }).then((rows) => rows as Issue[]),
enabled: !!selectedCompanyId && viewState.viewMode === "board" && !searchWithinLoadedIssues,
placeholderData: (previousData: Issue[] | undefined) => previousData,
@@ -1118,7 +1121,7 @@ export function IssuesList({
searchScopedIssues,
viewState,
currentUserId,
enableRoutineVisibilityFilter,
enableAgentCreatedVisibilityFilter,
liveIssueIds,
issueFilterContext,
);
@@ -1127,7 +1130,7 @@ export function IssuesList({
searchScopedIssues,
viewState,
currentUserId,
enableRoutineVisibilityFilter,
enableAgentCreatedVisibilityFilter,
liveIssueIds,
issueFilterContext,
]);
@@ -1185,7 +1188,7 @@ export function IssuesList({
enabled: !!selectedCompanyId,
});
const activeFilterCount = countActiveIssueFilters(viewState, enableRoutineVisibilityFilter);
const activeFilterCount = countActiveIssueFilters(viewState, enableAgentCreatedVisibilityFilter);
const boardHighVolume = viewState.viewMode === "board" && filtered.length > KANBAN_BOARD_HIGH_VOLUME_THRESHOLD;
const boardCompactCards =
viewState.boardCardDensity === "compact"
@@ -1203,7 +1206,13 @@ export function IssuesList({
|| viewState.boardColdLaneMode !== "auto"
|| viewState.boardColumnPageSize !== KANBAN_COLUMN_DEFAULT_PAGE_SIZE;
const groupedContent = useMemo(() => {
const hierarchyEnabled = enableAgentCreatedVisibilityFilter && !viewState.showAgentCreatedTasks && viewState.nestingEnabled && viewState.viewMode === "list";
const hierarchy = useIssueHierarchyContext(
selectedCompanyId, filtered.slice(0, renderedIssueRowLimit), viewState.collapsedParents,
hierarchyEnabled,
hierarchyRowBudget,
);
const baseGroupedContent = useMemo(() => {
if (viewState.groupBy === "none") {
return [{ key: "__all", label: null as string | null, items: filtered }];
}
@@ -1295,6 +1304,14 @@ export function IssuesList({
companyUserLabelMap,
projectById,
]);
const groupedContent = useMemo(() => baseGroupedContent.map((group) => ({
...group,
items: enableAgentCreatedVisibilityFilter && !viewState.showAgentCreatedTasks && viewState.nestingEnabled && viewState.viewMode === "list"
? includeIssueHierarchyContext(group.items, [...issues, ...hierarchy.issues])
: group.items,
})), [baseGroupedContent, hierarchy.issues, issues, enableAgentCreatedVisibilityFilter, viewState.showAgentCreatedTasks, viewState.nestingEnabled, viewState.viewMode]);
const visibleListRowCount = groupedContent.reduce((total, group) => total + group.items.length, 0);
// Flattened visible order (group headers, then tree DFS per group —
// collapsed groups keep their header entry but skip their rows) — must
@@ -1484,31 +1501,41 @@ export function IssuesList({
const previousIssueIds = renderedIssueIdsRef.current;
renderedIssueIdsRef.current = nextIssueIds;
const sameResultsOrAppend = previousIssueIds.length > 0 && nextIssueIds.startsWith(previousIssueIds);
if (!sameResultsOrAppend) setHierarchyRowBudget(INITIAL_ISSUE_ROW_RENDER_LIMIT);
setRenderedIssueRowLimit((current) => {
const nextInitialLimit = Math.min(filtered.length, INITIAL_ISSUE_ROW_RENDER_LIMIT);
const listAppended = previousIssueIds.length > 0
&& nextIssueIds.startsWith(previousIssueIds)
&& filtered.length >= current;
if (listAppended) return Math.min(filtered.length, Math.max(current, nextInitialLimit));
const nextInitialLimit = Math.min(visibleListRowCount, INITIAL_ISSUE_ROW_RENDER_LIMIT);
// Context arrives asynchronously and must not undo a reveal request.
if (hierarchyEnabled && sameResultsOrAppend) return Math.max(current, nextInitialLimit);
const listAppended = sameResultsOrAppend && visibleListRowCount >= current;
if (listAppended) return Math.min(visibleListRowCount, Math.max(current, nextInitialLimit));
return nextInitialLimit;
});
}, [filtered, viewState.viewMode]);
}, [filtered, visibleListRowCount, viewState.viewMode, hierarchyEnabled]);
const hasMoreRenderedRows = viewState.viewMode === "list" && renderedIssueRowLimit < filtered.length;
const remainingIssueRowCount = Math.max(filtered.length - renderedIssueRowLimit, 0);
const hasMoreHierarchyRows = hierarchyEnabled && hierarchy.hasMore;
const hasMoreRenderedRows = viewState.viewMode === "list" && renderedIssueRowLimit < visibleListRowCount;
const remainingIssueRowCount = Math.max(visibleListRowCount - renderedIssueRowLimit, 0);
const loadMoreIssueRows = useCallback(() => {
if (viewState.viewMode !== "list") return;
if (hasMoreHierarchyRows && !hierarchy.isFetching) {
setHierarchyRowBudget((current) => current + ISSUE_ROW_RENDER_BATCH_SIZE);
setRenderedIssueRowLimit((current) => current + ISSUE_ROW_RENDER_BATCH_SIZE);
return;
}
if (hasMoreRenderedRows) {
setRenderedIssueRowLimit((current) => Math.min(filtered.length, current + ISSUE_ROW_RENDER_BATCH_SIZE));
setRenderedIssueRowLimit((current) => Math.min(visibleListRowCount, current + ISSUE_ROW_RENDER_BATCH_SIZE));
return;
}
if (hasMoreIssues && !isLoadingMoreIssues) {
onLoadMoreIssues?.();
}
}, [
filtered.length,
visibleListRowCount,
hasMoreIssues,
hasMoreRenderedRows,
hasMoreHierarchyRows,
hierarchy.isFetching,
isLoadingMoreIssues,
onLoadMoreIssues,
viewState.viewMode,
@@ -1516,7 +1543,7 @@ export function IssuesList({
const canLoadMoreIssues = viewState.viewMode === "list"
&& !isLoading
&& (hasMoreRenderedRows || (hasMoreIssues && !isLoadingMoreIssues));
&& (hasMoreRenderedRows || (hasMoreHierarchyRows && !hierarchy.isFetching) || (hasMoreIssues && !isLoadingMoreIssues));
useEffect(() => {
if (!canLoadMoreIssues) return;
@@ -1624,8 +1651,11 @@ export function IssuesList({
const setIssueColumns = useCallback((next: InboxIssueColumn[]) => {
const normalized = normalizeInboxIssueColumns(next);
setVisibleIssueColumns(normalized);
saveIssueColumns(scopedKey, normalized);
}, [scopedKey]);
saveTaskCollectionPreferences({
companyId: selectedCompanyId ?? "__unscoped__", collectionKey: viewStateKey,
legacyViewStorageKey: scopedKey, legacyColumnsStorageKey: getIssueColumnsStorageKey(scopedKey),
}, { viewState, columns: normalized });
}, [scopedKey, selectedCompanyId, viewStateKey, viewState]);
const toggleIssueColumn = useCallback((column: InboxIssueColumn, enabled: boolean) => {
if (enabled) {
@@ -1803,7 +1833,7 @@ export function IssuesList({
labels={labels?.map((label) => ({ id: label.id, name: label.name, color: label.color }))}
currentUserId={currentUserId}
enableExternalObjectFilters={externalObjectsEnabled}
enableRoutineVisibilityFilter={enableRoutineVisibilityFilter}
enableAgentCreatedVisibilityFilter={enableAgentCreatedVisibilityFilter}
iconOnly
/>
@@ -1906,7 +1936,8 @@ export function IssuesList({
Some board columns are showing up to {ISSUE_BOARD_COLUMN_RESULT_LIMIT} tasks. Refine filters or search to reveal the rest.
</p>
)}
{!isLoading && !externalObjectFilterLoading && filtered.length === 0 && viewState.viewMode === "list" && (
{hierarchy.error ? <p className="text-sm text-destructive">Failed to load task hierarchy: {hierarchy.error.message}</p> : null}
{!isLoading && !externalObjectFilterLoading && visibleListRowCount === 0 && viewState.viewMode === "list" && (
<EmptyState
icon={CircleDot}
message="No tasks match the current filters or search."
@@ -2349,13 +2380,13 @@ export function IssuesList({
</Collapsible>
);
})}
{(remainingIssueRowCount > 0 || hasMoreIssues || isLoadingMoreIssues) && (
{(remainingIssueRowCount > 0 || hasMoreHierarchyRows || hasMoreIssues || isLoadingMoreIssues) && (
<div className="py-2" data-testid="issues-load-more-sentinel">
<p className="text-xs text-muted-foreground">
{isLoadingMoreIssues
{isLoadingMoreIssues || (hierarchyEnabled && hierarchy.isFetching)
? "Loading more tasks..."
: remainingIssueRowCount > 0
? `Rendering ${Math.min(renderedIssueRowLimit, filtered.length)} of ${filtered.length} tasks`
? `Rendering ${Math.min(renderedIssueRowLimit, visibleListRowCount)} of ${visibleListRowCount} tasks`
: "Scroll to load more tasks"}
</p>
</div>
+50
View File
@@ -0,0 +1,50 @@
import { loadIssueHierarchyChildren } from "../lib/issue-hierarchy-context";
import { useQueries, useQuery } from "@tanstack/react-query";
import type { Issue } from "@paperclipai/shared";
import { issuesApi } from "../api/issues";
import { ApiError } from "../api/client";
import { queryKeys } from "../lib/queryKeys";
export function useIssueHierarchyContext(companyId: string | null, matches: Issue[], collapsedParents: string[], enabled: boolean, rowBudget: number) {
const parents = [...new Set(matches.map((issue) => issue.parentId).filter((id): id is string => Boolean(id)))];
const ancestorQueries = useQueries({ queries: parents.map((parentId) => ({
queryKey: [...queryKeys.issues.list(companyId ?? "__unscoped__"), "hierarchy-ancestors", parentId],
enabled: enabled && Boolean(companyId),
staleTime: 30_000,
queryFn: async ({ signal }: { signal: AbortSignal }) => {
const ancestors: Issue[] = [];
const visited = new Set<string>();
let id: string | null = parentId;
while (id && !visited.has(id)) {
visited.add(id);
try {
const parent: Issue = await issuesApi.get(id, { signal });
if (parent.companyId !== companyId) break;
ancestors.push(parent);
id = parent.parentId;
} catch (error) {
if (error instanceof ApiError && (error.status === 403 || error.status === 404)) break;
throw error;
}
}
return ancestors;
},
})) });
const children = useQuery<Awaited<ReturnType<typeof loadIssueHierarchyChildren>>>({
queryKey: [...queryKeys.issues.list(companyId ?? "__unscoped__"), "hierarchy-children", matches.map((issue) => issue.id), collapsedParents, rowBudget],
enabled: enabled && Boolean(companyId) && matches.length > 0,
staleTime: 30_000,
placeholderData: (previous) => previous ? {
...previous, issues: previous.issues.filter((issue) => issue.companyId === companyId),
} : undefined,
queryFn: ({ signal }) => loadIssueHierarchyChildren(companyId!, matches, collapsedParents, rowBudget,
(parentId, limit, offset) => issuesApi.list(companyId!, { parentId, limit, offset, includeRoutineExecutions: true }, { signal })),
});
const queries = [...ancestorQueries, children];
return {
issues: [...ancestorQueries.flatMap((query) => query.data ?? []), ...(children.data?.issues ?? [])],
hasMore: children.data?.hasMore ?? false,
isFetching: children.isFetching,
error: queries.find((query) => query.error)?.error,
};
}
+30
View File
@@ -0,0 +1,30 @@
import { useCallback, useSyncExternalStore } from "react";
import { taskCollectionPreferencesStorageKey, TASK_COLLECTION_PREFERENCES_CHANGED, TASK_COLLECTION_PREFERENCES_VERSION } from "../lib/task-collection-preferences";
/** Subscribe the collection's fetching owner to its persisted filter control. */
export function useShowAgentCreatedTasks(companyId: string | null, collectionKey: string): boolean {
const getSnapshot = useCallback(() => {
try {
const key = taskCollectionPreferencesStorageKey({ companyId: companyId ?? "__unscoped__", collectionKey });
const current = localStorage.getItem(key);
const legacy = localStorage.getItem(companyId ? `${collectionKey}:${companyId}` : collectionKey);
const envelope = current ? JSON.parse(current) : null;
const valid = envelope?.version === TASK_COLLECTION_PREFERENCES_VERSION
&& envelope.companyId === (companyId ?? "__unscoped__") && envelope.collectionKey === collectionKey;
const view = valid ? envelope.viewState : legacy ? JSON.parse(legacy) : null;
return view?.showAgentCreatedTasks === true;
} catch {
return false;
}
}, [companyId, collectionKey]);
return useSyncExternalStore(subscribe, getSnapshot, () => false);
}
function subscribe(onChange: () => void) {
window.addEventListener(TASK_COLLECTION_PREFERENCES_CHANGED, onChange);
window.addEventListener("storage", onChange);
return () => {
window.removeEventListener(TASK_COLLECTION_PREFERENCES_CHANGED, onChange);
window.removeEventListener("storage", onChange);
};
}
+10 -18
View File
@@ -18,7 +18,6 @@ import {
buildInboxKeyboardNavEntries,
buildInboxDismissedAtByKey,
computeInboxBadgeData,
filterInboxIssues,
getArchivedInboxSearchIssues,
getAvailableInboxIssueColumns,
getInboxWorkItemKey,
@@ -943,7 +942,7 @@ describe("inbox helpers", () => {
workspaces: [],
liveOnly: false,
externalObjectStatuses: [],
hideRoutineExecutions: true,
showAgentCreatedTasks: false,
},
}).map((issue) => issue.id),
).toEqual(["remote-match"]);
@@ -964,7 +963,7 @@ describe("inbox helpers", () => {
workspaces: [],
liveOnly: false,
externalObjectStatuses: [],
hideRoutineExecutions: true,
showAgentCreatedTasks: false,
},
}),
).toEqual([]);
@@ -985,7 +984,7 @@ describe("inbox helpers", () => {
workspaces: [],
liveOnly: false,
externalObjectStatuses: [],
hideRoutineExecutions: true,
showAgentCreatedTasks: false,
},
}),
).toEqual([]);
@@ -1033,7 +1032,7 @@ describe("inbox helpers", () => {
workspaces: [],
liveOnly: false,
externalObjectStatuses: ["failed"],
hideRoutineExecutions: true,
showAgentCreatedTasks: false,
},
issueFilterContext: {
externalObjectSummaryByIssueId: summaries,
@@ -1129,7 +1128,7 @@ describe("inbox helpers", () => {
workspaces: ["workspace-1"],
liveOnly: true,
externalObjectStatuses: [],
hideRoutineExecutions: false,
showAgentCreatedTasks: true,
},
});
saveInboxFilterPreferences("company-2", {
@@ -1145,7 +1144,7 @@ describe("inbox helpers", () => {
workspaces: [],
liveOnly: false,
externalObjectStatuses: [],
hideRoutineExecutions: true,
showAgentCreatedTasks: false,
},
});
@@ -1162,7 +1161,7 @@ describe("inbox helpers", () => {
workspaces: [],
liveOnly: true,
externalObjectStatuses: [],
hideRoutineExecutions: false,
showAgentCreatedTasks: true,
},
});
expect(loadInboxFilterPreferences("company-2")).toEqual({
@@ -1178,7 +1177,7 @@ describe("inbox helpers", () => {
workspaces: [],
liveOnly: false,
externalObjectStatuses: [],
hideRoutineExecutions: true,
showAgentCreatedTasks: false,
},
});
});
@@ -1196,7 +1195,7 @@ describe("inbox helpers", () => {
projects: ["project-1"],
workspaces: ["workspace-1", false],
liveOnly: "yes",
hideRoutineExecutions: "yes",
showAgentCreatedTasks: "yes",
},
}));
@@ -1213,7 +1212,7 @@ describe("inbox helpers", () => {
workspaces: [],
liveOnly: false,
externalObjectStatuses: [],
hideRoutineExecutions: false,
showAgentCreatedTasks: false,
},
});
});
@@ -1377,13 +1376,6 @@ describe("inbox helpers", () => {
expect(getInboxKeyboardSelectionIndex(0, 3, "previous")).toBe(0);
});
it("hides routine execution issues when the hide toggle is enabled", () => {
const manualIssue = { ...makeIssue("manual", true), originKind: "manual" as const };
const routineIssue = { ...makeIssue("routine", true), originKind: "routine_execution" as const };
expect(filterInboxIssues([manualIssue, routineIssue], false)).toEqual([manualIssue, routineIssue]);
expect(filterInboxIssues([manualIssue, routineIssue], true)).toEqual([manualIssue]);
});
it("groups mixed inbox items by type while preserving item order within each group", () => {
const items: InboxWorkItem[] = [
+3 -13
View File
@@ -425,17 +425,7 @@ export function shouldResetInboxWorkspaceGrouping(
return experimentalSettingsLoaded && groupBy === "workspace" && !isolatedWorkspacesEnabled;
}
export function shouldIncludeRoutineExecutionIssue(
issue: Pick<Issue, "originKind">,
hideRoutineExecutions: boolean,
): boolean {
return !hideRoutineExecutions || issue.originKind !== "routine_execution";
}
export function filterInboxIssues(issues: Issue[], hideRoutineExecutions: boolean): Issue[] {
if (!hideRoutineExecutions) return issues;
return issues.filter((issue) => shouldIncludeRoutineExecutionIssue(issue, hideRoutineExecutions));
}
export function matchesInboxIssueSearch(
issue: Pick<Issue, "title" | "identifier" | "description" | "executionWorkspaceId" | "projectId" | "projectWorkspaceId">,
@@ -505,7 +495,7 @@ export function getInboxSearchSupplementIssues({
remoteIssues,
issueFilters,
currentUserId,
enableRoutineVisibilityFilter = false,
enableAgentCreatedVisibilityFilter = false,
liveIssueIds,
issueFilterContext = {},
}: {
@@ -515,7 +505,7 @@ export function getInboxSearchSupplementIssues({
remoteIssues: Issue[];
issueFilters: IssueFilterState;
currentUserId?: string | null;
enableRoutineVisibilityFilter?: boolean;
enableAgentCreatedVisibilityFilter?: boolean;
liveIssueIds?: ReadonlySet<string>;
issueFilterContext?: IssueFilterWorkspaceContext;
}): Issue[] {
@@ -531,7 +521,7 @@ export function getInboxSearchSupplementIssues({
remoteIssues,
issueFilters,
currentUserId,
enableRoutineVisibilityFilter,
enableAgentCreatedVisibilityFilter,
liveIssueIds,
issueFilterContext,
)
+17
View File
@@ -6,6 +6,7 @@ import {
applyIssueFilters,
countActiveIssueFilters,
defaultIssueFilterState,
normalizeIssueFilterState,
resolveIssueFilterWorkspaceId,
searchIssueFilterOptions,
shouldIncludeIssueFilterWorkspaceOption,
@@ -69,6 +70,22 @@ function makeExternalObjectSummary(overrides: Partial<ExternalObjectSummary> = {
}
describe("issue filters", () => {
it("hides automation by default while an opt-in includes every creation source", () => {
const issues = [makeIssue({ id: "human", createdByUserId: "person" }), makeIssue({ id: "agent", createdByAgentId: "agent" }), makeIssue({ id: "routine", originKind: "routine_execution", createdByUserId: "person" }), makeIssue({ id: "system" })];
expect(applyIssueFilters(issues, defaultIssueFilterState, null, true).map((issue) => issue.id)).toEqual(["human"]);
expect(applyIssueFilters(issues, { ...defaultIssueFilterState, showAgentCreatedTasks: true }, null, true)).toEqual(issues);
// Membership and task-detail collections can explicitly bypass creation visibility.
expect(applyIssueFilters(issues, defaultIssueFilterState, null, false)).toEqual(issues);
expect(countActiveIssueFilters(defaultIssueFilterState, true)).toBe(0);
expect(countActiveIssueFilters({ ...defaultIssueFilterState, showAgentCreatedTasks: true }, true)).toBe(1);
});
it("defaults legacy and invalid preferences to hidden without losing other filters", () => {
expect(normalizeIssueFilterState({ hideRoutineExecutions: false, statuses: ["todo"] })).toMatchObject({ showAgentCreatedTasks: false, statuses: ["todo"] });
expect(normalizeIssueFilterState({ showAgentCreatedTasks: "true" }).showAgentCreatedTasks).toBe(false);
expect(normalizeIssueFilterState({ showAgentCreatedTasks: true }).showAgentCreatedTasks).toBe(true);
});
it("searches filter options case-insensitively without mutating the source", () => {
const options = [{ name: "Alpha Agent" }, { name: "Release QA" }];
expect(searchIssueFilterOptions(options, " qa ", (option) => option.name)).toEqual([
+9 -9
View File
@@ -1,4 +1,4 @@
import type { ExternalObjectSummary, Issue } from "@paperclipai/shared";
import { isAgentCreatedIssue, type ExternalObjectSummary, type Issue } from "@paperclipai/shared";
export type IssueFilterWorkspaceLookup = {
mode?: string | null;
@@ -36,7 +36,7 @@ export type IssueFilterState = {
* - `none` — issues with zero external objects
*/
externalObjectStatuses: string[];
hideRoutineExecutions: boolean;
showAgentCreatedTasks: boolean;
};
export const defaultIssueFilterState: IssueFilterState = {
@@ -49,7 +49,7 @@ export const defaultIssueFilterState: IssueFilterState = {
workspaces: [],
liveOnly: false,
externalObjectStatuses: [],
hideRoutineExecutions: false,
showAgentCreatedTasks: false,
};
export const externalObjectFilterOrder = [
@@ -115,7 +115,7 @@ export function normalizeIssueFilterState(value: unknown): IssueFilterState {
workspaces: normalizeIssueFilterValueArray(candidate.workspaces),
liveOnly: candidate.liveOnly === true,
externalObjectStatuses: normalizeIssueFilterValueArray(candidate.externalObjectStatuses),
hideRoutineExecutions: candidate.hideRoutineExecutions === true,
showAgentCreatedTasks: candidate.showAgentCreatedTasks === true,
};
}
@@ -210,7 +210,7 @@ export function applyIssueFilters(
issues: Issue[],
state: IssueFilterState,
currentUserId?: string | null,
enableRoutineVisibilityFilter = false,
enableAgentCreatedVisibilityFilter = false,
liveIssueIds?: ReadonlySet<string>,
workspaceContext: IssueFilterWorkspaceContext = {},
): Issue[] {
@@ -218,8 +218,8 @@ export function applyIssueFilters(
if (state.liveOnly) {
result = result.filter((issue) => liveIssueIds?.has(issue.id) === true);
}
if (enableRoutineVisibilityFilter && state.hideRoutineExecutions) {
result = result.filter((issue) => issue.originKind !== "routine_execution");
if (enableAgentCreatedVisibilityFilter && !state.showAgentCreatedTasks) {
result = result.filter((issue) => !isAgentCreatedIssue(issue));
}
if (state.statuses.length > 0) result = result.filter((issue) => state.statuses.includes(issue.status));
if (state.priorities.length > 0) result = result.filter((issue) => state.priorities.includes(issue.priority));
@@ -269,7 +269,7 @@ export function applyIssueFilters(
export function countActiveIssueFilters(
state: IssueFilterState,
enableRoutineVisibilityFilter = false,
enableAgentCreatedVisibilityFilter = false,
): number {
let count = 0;
if (state.statuses.length > 0) count += 1;
@@ -281,6 +281,6 @@ export function countActiveIssueFilters(
if (state.workspaces.length > 0) count += 1;
if (state.liveOnly) count += 1;
if (state.externalObjectStatuses.length > 0) count += 1;
if (enableRoutineVisibilityFilter && state.hideRoutineExecutions) count += 1;
if (enableAgentCreatedVisibilityFilter && state.showAgentCreatedTasks) count += 1;
return count;
}
@@ -0,0 +1,50 @@
import { describe, expect, it } from "vitest";
import type { Issue } from "@paperclipai/shared";
import { includeIssueHierarchyContext, loadIssueHierarchyChildren } from "./issue-hierarchy-context";
const task = (id: string, parentId: string | null = null) => ({ id, parentId, companyId: "company" } as Issue);
describe("task hierarchy context", () => {
it("retains ancestors and descendants without promoting siblings or orphans", () => {
const match = task("human", "agent-parent");
const context = [task("agent-parent", "grandparent"), task("grandparent"), task("agent-child", "human"), task("grandchild", "agent-child"), task("unrelated"), task("orphan", "missing"), task("sibling", "agent-parent")];
expect(includeIssueHierarchyContext([match], context).map((issue) => issue.id)).toEqual([
"human", "agent-parent", "grandparent", "agent-child", "grandchild",
]);
expect(includeIssueHierarchyContext([], context)).toEqual([]);
});
it("deduplicates matches and terminates cycles", () => {
const match = task("human", "parent");
expect(includeIssueHierarchyContext([match], [match, task("parent", "human")]).map((issue) => issue.id)).toEqual(["human", "parent"]);
});
});
describe("bounded hierarchy reads", () => {
it("caps rows and requests, and shares overlapping matching subtrees", async () => {
const root = task("root");
const child = task("child", "root");
const calls: string[] = [];
const read = async (id: string, limit: number, offset: number) => {
calls.push(id);
const rows = id === "root" ? [child] : id === "child"
? Array.from({ length: 500 }, (_, index) => task(`nested-${index}`, "child")) : [];
return rows.slice(offset, offset + limit);
};
const first = await loadIssueHierarchyChildren("company", [root, child], [], 5, read);
expect(first.issues).toHaveLength(5);
expect(first.hasMore).toBe(true);
expect(calls).toEqual(["root", "child"]);
calls.length = 0;
expect((await loadIssueHierarchyChildren("company", [root, child], [], 10, read)).issues).toHaveLength(10);
expect(calls).toEqual(["root", "child"]);
});
it("probes collapsed parents without fetching their tree and rejects foreign-company rows", async () => {
const calls: Array<[string, number]> = [];
const rows = await loadIssueHierarchyChildren("company", [task("root")], ["root"], 5,
async (id, limit) => { calls.push([id, limit]); return [task("child", "root")]; });
expect(rows.issues.map((issue) => issue.id)).toEqual(["child"]);
expect(calls).toEqual([["root", 1]]);
expect(await loadIssueHierarchyChildren("company", [task("root")], [], 1,
async () => [{ ...task("foreign", "root"), companyId: "other" }])).toEqual({ issues: [], hasMore: true });
});
});
+64
View File
@@ -0,0 +1,64 @@
import type { Issue } from "@paperclipai/shared";
/** Context never promotes an unrelated or orphaned automated task to a result. */
export function includeIssueHierarchyContext(matches: Issue[], context: Issue[]): Issue[] {
const byId = new Map([...context, ...matches].map((issue) => [issue.id, issue]));
const result = new Map(matches.map((issue) => [issue.id, issue]));
for (const match of matches) {
const visited = new Set([match.id]);
let parentId = match.parentId;
while (parentId && !visited.has(parentId)) {
visited.add(parentId);
const parent = byId.get(parentId);
if (!parent) break;
result.set(parent.id, parent);
parentId = parent.parentId;
}
}
// Descendants are rooted at matches, not at contextual ancestors.
const descendantIds = new Set(matches.map((issue) => issue.id));
let changed = true;
while (changed) {
changed = false;
for (const issue of context) {
if (!descendantIds.has(issue.id) && issue.parentId && descendantIds.has(issue.parentId)) {
descendantIds.add(issue.id);
result.set(issue.id, issue);
changed = true;
}
}
}
return [...result.values()];
}
/** Fetch each parent once and stop at the collection's current rendering budget. */
export async function loadIssueHierarchyChildren(
companyId: string,
matches: Issue[],
collapsedParents: string[],
rowBudget: number,
readChildren: (parentId: string, limit: number, offset: number) => Promise<Issue[]>,
): Promise<{ issues: Issue[]; hasMore: boolean }> {
const context: Issue[] = [];
const queue = matches.map((issue) => ({ issue, offset: 0 }));
const visited = new Set<string>();
const fetched = new Set<string>();
let requests = 0;
while (queue.length > 0 && context.length < rowBudget && requests < rowBudget) {
const { issue, offset } = queue.shift()!;
if (offset === 0 && visited.has(issue.id)) continue;
visited.add(issue.id);
const collapsed = collapsedParents.includes(issue.id);
const limit = collapsed ? 1 : Math.min(100, rowBudget - context.length);
const rows = await readChildren(issue.id, limit, offset);
requests += 1;
for (const child of rows) {
if (child.companyId !== companyId || fetched.has(child.id)) continue;
fetched.add(child.id);
context.push(child);
if (!collapsed) queue.push({ issue: child, offset: 0 });
}
if (!collapsed && rows.length === limit) queue.unshift({ issue, offset: offset + rows.length });
}
return { issues: context, hasMore: queue.length > 0 };
}
@@ -1,3 +1,5 @@
export const TASK_COLLECTION_PREFERENCES_CHANGED = "paperclip:task-collection-preferences-changed";
export const TASK_COLLECTION_PREFERENCES_VERSION = 1 as const;
type StorageLike = Pick<Storage, "getItem" | "setItem">;
@@ -79,6 +81,9 @@ export function saveTaskCollectionPreferences<TViewState, TColumn extends string
try {
storage.setItem(taskCollectionPreferencesStorageKey(location), JSON.stringify(envelope));
if (typeof window !== "undefined" && storage === browserStorage()) {
queueMicrotask(() => window.dispatchEvent(new Event(TASK_COLLECTION_PREFERENCES_CHANGED)));
}
// Dual-write during migration so older builds using the same worktree keep
// reading the latest presentation state.
if (location.legacyViewStorageKey) {
+8 -6
View File
@@ -1114,17 +1114,19 @@ function StreamlinedInbox({
...queryKeys.issues.search(selectedCompanyId!, normalizedSearchQuery, undefined, 25),
"compact",
"inbox-supplement",
issueFilters.showAgentCreatedTasks,
"live-descendant-summary",
],
queryFn: () =>
issuesApi.listCompact(selectedCompanyId!, {
q: normalizedSearchQuery,
limit: 25,
includeAgentCreatedTasks: issueFilters.showAgentCreatedTasks,
includeParticipatedTasks: true,
includeRoutineExecutions: true,
includeLiveDescendantSummary: true,
}).then((rows) => rows as Issue[]),
enabled: shouldUseIssueSearchSupplement,
placeholderData: (previousData) => previousData,
});
const liveIssueIds = useMemo(
() => collectLiveIssueIds(liveRuns, [
@@ -1155,11 +1157,11 @@ function StreamlinedInbox({
externalObjectSummariesReady: externalObjectSummariesReady && !externalObjectSummariesLoading,
}), [externalObjectSummariesLoading, externalObjectSummariesReady, externalObjectSummaryByIssueId]);
const visibleMineIssues = useMemo(
() => applyIssueFilters(mineIssues, issueFilters, currentUserId, true, liveIssueIds, issueFilterContext),
() => applyIssueFilters(mineIssues, issueFilters, currentUserId, false, liveIssueIds, issueFilterContext),
[mineIssues, issueFilters, currentUserId, liveIssueIds, issueFilterContext],
);
const visibleTouchedIssues = useMemo(
() => applyIssueFilters(touchedIssues, issueFilters, currentUserId, true, liveIssueIds, issueFilterContext),
() => applyIssueFilters(touchedIssues, issueFilters, currentUserId, false, liveIssueIds, issueFilterContext),
[touchedIssues, issueFilters, currentUserId, liveIssueIds, issueFilterContext],
);
const unreadTouchedIssues = useMemo(
@@ -1466,7 +1468,7 @@ function StreamlinedInbox({
remoteIssues: remoteIssueSearchResults,
issueFilters,
currentUserId,
enableRoutineVisibilityFilter: true,
enableAgentCreatedVisibilityFilter: false,
liveIssueIds,
issueFilterContext,
}),
@@ -2485,7 +2487,7 @@ function StreamlinedInbox({
labels={labels?.map((label) => ({ id: label.id, name: label.name, color: label.color }))}
currentUserId={currentUserId}
enableExternalObjectFilters={externalObjectsEnabled}
enableRoutineVisibilityFilter
enableAgentCreatedVisibilityFilter
buttonVariant="outline"
iconOnly
presentation={streamlinedUiEnabled ? "streamlined" : "legacy"}
@@ -2590,7 +2592,7 @@ function StreamlinedInbox({
labels={labels?.map((label) => ({ id: label.id, name: label.name, color: label.color }))}
currentUserId={currentUserId}
enableExternalObjectFilters={externalObjectsEnabled}
enableRoutineVisibilityFilter
enableAgentCreatedVisibilityFilter
buttonVariant="outline"
iconOnly
presentation={streamlinedUiEnabled ? "streamlined" : "legacy"}
+5 -1
View File
@@ -1,3 +1,4 @@
import { useShowAgentCreatedTasks } from "../hooks/useShowAgentCreatedTasks";
import { useEffect, useMemo, useCallback, useRef, useState } from "react";
import type { ReactNode } from "react";
import { useLocation, useNavigate, useSearchParams } from "@/lib/router";
@@ -179,6 +180,7 @@ function OrganizationIssues({
}
return urlSearch;
}, [searchOverride, urlSearch, location.search]);
const showAgentCreatedTasks = useShowAgentCreatedTasks(selectedCompanyId, "paperclip:issues-view");
const participantAgentId = searchParams.get("participantAgentId") ?? undefined;
const initialWorkspaces = searchParams.getAll("workspace").filter((workspaceId) => workspaceId.length > 0);
const workspaceIdFilter = initialWorkspaces.length === 1 ? initialWorkspaces[0] : undefined;
@@ -254,6 +256,7 @@ function OrganizationIssues({
workspaceIdFilter ?? "__all__",
"compact",
"with-routine-executions",
showAgentCreatedTasks,
"infinite",
issuePageSize,
],
@@ -261,6 +264,7 @@ function OrganizationIssues({
participantAgentId,
workspaceId: workspaceIdFilter,
includeRoutineExecutions: true,
includeAgentCreatedTasks: showAgentCreatedTasks,
limit: issuePageSize,
offset: pageParam,
sortField: "updated",
@@ -323,7 +327,7 @@ function OrganizationIssues({
toolbarContext={toolbarContext}
initialSearch={syncedSearch}
onSearchChange={handleSearchChange}
enableRoutineVisibilityFilter
enableAgentCreatedVisibilityFilter
hasMoreIssues={hasMoreServerIssues}
onLoadMoreIssues={loadMoreServerIssues}
onUpdateIssue={(id, data) => updateIssue.mutate({ id, data })}
+8 -6
View File
@@ -974,17 +974,19 @@ export function Inbox() {
...queryKeys.issues.search(selectedCompanyId!, normalizedSearchQuery, undefined, 25),
"compact",
"inbox-supplement",
issueFilters.showAgentCreatedTasks,
"live-descendant-summary",
],
queryFn: () =>
issuesApi.listCompact(selectedCompanyId!, {
q: normalizedSearchQuery,
limit: 25,
includeAgentCreatedTasks: issueFilters.showAgentCreatedTasks,
includeParticipatedTasks: true,
includeRoutineExecutions: true,
includeLiveDescendantSummary: true,
}).then((rows) => rows as Issue[]),
enabled: shouldUseIssueSearchSupplement,
placeholderData: (previousData) => previousData,
});
const liveIssueIds = useMemo(
() => collectLiveIssueIds(liveRuns, [
@@ -1015,11 +1017,11 @@ export function Inbox() {
externalObjectSummariesReady: externalObjectSummariesReady && !externalObjectSummariesLoading,
}), [externalObjectSummariesLoading, externalObjectSummariesReady, externalObjectSummaryByIssueId]);
const visibleMineIssues = useMemo(
() => applyIssueFilters(mineIssues, issueFilters, currentUserId, true, liveIssueIds, issueFilterContext),
() => applyIssueFilters(mineIssues, issueFilters, currentUserId, false, liveIssueIds, issueFilterContext),
[mineIssues, issueFilters, currentUserId, liveIssueIds, issueFilterContext],
);
const visibleTouchedIssues = useMemo(
() => applyIssueFilters(touchedIssues, issueFilters, currentUserId, true, liveIssueIds, issueFilterContext),
() => applyIssueFilters(touchedIssues, issueFilters, currentUserId, false, liveIssueIds, issueFilterContext),
[touchedIssues, issueFilters, currentUserId, liveIssueIds, issueFilterContext],
);
const unreadTouchedIssues = useMemo(
@@ -1321,7 +1323,7 @@ export function Inbox() {
remoteIssues: remoteIssueSearchResults,
issueFilters,
currentUserId,
enableRoutineVisibilityFilter: true,
enableAgentCreatedVisibilityFilter: false,
liveIssueIds,
issueFilterContext,
}),
@@ -2350,7 +2352,7 @@ export function Inbox() {
labels={labels?.map((label) => ({ id: label.id, name: label.name, color: label.color }))}
currentUserId={currentUserId}
enableExternalObjectFilters={externalObjectsEnabled}
enableRoutineVisibilityFilter
enableAgentCreatedVisibilityFilter
buttonVariant="outline"
iconOnly
/>
@@ -2448,7 +2450,7 @@ export function Inbox() {
labels={labels?.map((label) => ({ id: label.id, name: label.name, color: label.color }))}
currentUserId={currentUserId}
enableExternalObjectFilters={externalObjectsEnabled}
enableRoutineVisibilityFilter
enableAgentCreatedVisibilityFilter
buttonVariant="outline"
iconOnly
/>
+5 -2
View File
@@ -1,3 +1,4 @@
import { useShowAgentCreatedTasks } from "../hooks/useShowAgentCreatedTasks";
import { useCallback, useEffect, useMemo, useState, useRef } from "react";
import { Link, useParams, useNavigate, useLocation, Navigate } from "@/lib/router";
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
@@ -186,6 +187,7 @@ function ProjectTilePicker({
/* ── List (issues) tab content ── */
function ProjectIssuesList({ projectId, companyId }: { projectId: string; companyId: string }) {
const showAgentCreatedTasks = useShowAgentCreatedTasks(companyId, "paperclip:project-issues-view");
const queryClient = useQueryClient();
const { data: agents } = useQuery({
@@ -218,8 +220,8 @@ function ProjectIssuesList({ projectId, companyId }: { projectId: string; compan
});
const { data: issues, isLoading, error } = useQuery({
queryKey: queryKeys.issues.listByProject(companyId, projectId),
queryFn: () => issuesApi.list(companyId, { projectId }),
queryKey: [...queryKeys.issues.listByProject(companyId, projectId), showAgentCreatedTasks],
queryFn: () => issuesApi.listAll(companyId, { projectId, includeRoutineExecutions: true, includeAgentCreatedTasks: showAgentCreatedTasks }),
enabled: !!companyId,
});
const liveIssueIds = useMemo(() => collectLiveIssueIds(liveRuns, issues), [issues, liveRuns]);
@@ -242,6 +244,7 @@ function ProjectIssuesList({ projectId, companyId }: { projectId: string; compan
projects={projects}
liveIssueIds={liveIssueIds}
projectId={projectId}
enableAgentCreatedVisibilityFilter
viewStateKey="paperclip:project-issues-view"
onUpdateIssue={(id, data) => updateIssue.mutate({ id, data })}
/>
+6 -1
View File
@@ -171,7 +171,7 @@
{
"id": "inbox-search",
"title": "Inbox, decisions, and search",
"description": "Personal triage, decision queues, unread/blocked views, and search.",
"description": "Personal triage, decision queues, unread/blocked views, search, and personal task toasts.",
"capabilities": [
{
"id": "inbox-search/views",
@@ -192,6 +192,11 @@
"id": "inbox-search/search",
"label": "Search",
"description": "query company work and follow a result to its original record."
},
{
"id": "inbox-search/toasts",
"label": "Toasts",
"description": "receive live task notifications only for personal participation or explicit mentions."
}
]
},
@@ -647,7 +647,7 @@ function FilterPopoverWithExternalChecked() {
projects={storybookProjects.map((project) => ({ id: project.id, name: project.name }))}
labels={storybookIssueLabels.map((label) => ({ id: label.id, name: label.name, color: label.color }))}
currentUserId="user-board"
enableRoutineVisibilityFilter
enableAgentCreatedVisibilityFilter
buttonVariant="outline"
creators={[
{ id: "user:user-board", label: "Riley Board", kind: "user", searchText: "board user human" },
@@ -1,5 +1,6 @@
import { useEffect, useMemo, useRef, useState } from "react";
import type { Meta, StoryObj } from "@storybook/react-vite";
import { creationVisibilityStories } from "../../support/issue-creation-visibility";
import type { Issue, IssueLabel, Project } from "@paperclipai/shared";
import type { RunForIssue } from "@/api/activity";
import { useQueryClient } from "@tanstack/react-query";
@@ -594,7 +595,7 @@ function OpenFiltersPopover() {
projects={storybookProjects.map((project) => ({ id: project.id, name: project.name }))}
labels={storybookIssueLabels.map((label) => ({ id: label.id, name: label.name, color: label.color }))}
currentUserId="user-board"
enableRoutineVisibilityFilter
enableAgentCreatedVisibilityFilter
buttonVariant="outline"
creators={[
{ id: "user:user-board", label: "Riley Board", kind: "user", searchText: "board user human" },
@@ -771,7 +772,7 @@ function IssueManagementStories() {
viewStateKey={issueListViewKey}
onUpdateIssue={() => undefined}
createIssueLabel="issue"
enableRoutineVisibilityFilter
enableAgentCreatedVisibilityFilter
/>
</Section>
@@ -939,3 +940,20 @@ export const IssuePropertiesRelationshipBadgesInline: Story = {
name: "IssueProperties - relationship badges inline",
render: () => <IssuePropertiesRelationshipBadgesPane inline />,
};
export const AgentCreatedTasksHidden: Story = {
...creationVisibilityStories.hidden,
name: "Agent-created tasks — hidden by default",
play: creationVisibilityStories.hidden.play,
};
export const AgentCreatedTasksIncluded: Story = {
...creationVisibilityStories.included,
name: "Agent-created tasks — explicit opt-in",
play: creationVisibilityStories.included.play,
};
export const AgentCreatedTasksFilter: Story = {
...creationVisibilityStories.filter,
name: "Agent-created tasks — filter control",
play: creationVisibilityStories.filter.play,
};
@@ -0,0 +1,103 @@
import { useState } from "react";
import type { StoryObj } from "@storybook/react-vite";
import { expect, within } from "storybook/test";
import { useQueryClient } from "@tanstack/react-query";
import { IssuesList } from "@/components/IssuesList";
import { defaultIssueFilterState } from "@/lib/issue-filters";
import { saveTaskCollectionPreferences } from "@/lib/task-collection-preferences";
import { queryKeys } from "@/lib/queryKeys";
import { createIssue, storybookAgents, storybookAuthSession, storybookCompanies, storybookProjects } from "../fixtures/paperclipData";
const companyId = "company-storybook";
type Story = StoryObj;
function hydrateStorybookQueries(queryClient: ReturnType<typeof useQueryClient>) {
queryClient.setQueryData(queryKeys.companies.all, { companies: storybookCompanies, unauthorized: false });
queryClient.setQueryData(queryKeys.auth.session, storybookAuthSession);
queryClient.setQueryData(queryKeys.agents.list(companyId), storybookAgents);
queryClient.setQueryData(queryKeys.projects.list(companyId), storybookProjects);
queryClient.setQueryData(queryKeys.instance.experimentalSettings, { enableIsolatedWorkspaces: false, enableStreamlinedUi: true });
}
const creationVisibilityTasks = [
createIssue({ id: "visibility-human", identifier: "PAP-1701", title: "Human request", createdByUserId: "user-board", createdByAgentId: null }),
createIssue({ id: "visibility-agent", identifier: "PAP-1702", title: "Agent root task", createdByUserId: null, createdByAgentId: "agent-codex" }),
createIssue({ id: "visibility-channel", identifier: "PAP-1707", title: "Chat channel task", originKind: "chat_channel", createdByUserId: "user-board", createdByAgentId: null }),
createIssue({ id: "visibility-routine", identifier: "PAP-1703", title: "Scheduled routine run", originKind: "routine_execution", createdByUserId: null, createdByAgentId: null, responsibleUserId: "user-board" }),
createIssue({ id: "visibility-child", identifier: "PAP-1704", title: "Agent subtask", parentId: "visibility-human", createdByUserId: null, createdByAgentId: "agent-codex" }),
createIssue({ id: "visibility-ancestor", identifier: "PAP-1705", title: "Agent ancestor", createdByUserId: null, createdByAgentId: "agent-codex" }),
createIssue({ id: "visibility-human-child", identifier: "PAP-1706", title: "Human follow-up", parentId: "visibility-ancestor", createdByUserId: "user-board", createdByAgentId: null }),
].map((issue) => ({ ...issue, status: "todo" as const, checkoutRunId: null, executionRunId: null, executionAgentNameKey: null, executionLockedAt: null, executionWorkspaceId: null, currentExecutionWorkspace: null, startedAt: null, labelIds: [], labels: [] }));
function CreationVisibilityStory({ included = false }: { included?: boolean }) {
const queryClient = useQueryClient();
const viewStateKey = `storybook:agent-created-tasks:${included ? "included" : "hidden"}`;
useState(() => {
hydrateStorybookQueries(queryClient);
saveTaskCollectionPreferences({ companyId, collectionKey: viewStateKey, legacyViewStorageKey: `${viewStateKey}:${companyId}` }, {
viewState: { ...defaultIssueFilterState, showAgentCreatedTasks: included, viewMode: "list", groupBy: "none", sortField: "updated", sortDir: "desc", nestingEnabled: true, collapsedParents: [], collapsedGroups: [] },
columns: ["status", "id", "assignee", "updated"],
});
const listKey = queryKeys.issues.list(companyId);
const ancestor = creationVisibilityTasks.find((issue) => issue.id === "visibility-ancestor")!;
queryClient.setQueryData([...listKey, "hierarchy-ancestors", ancestor.id], [ancestor]);
queryClient.setQueryData([...listKey, "hierarchy-children", ["visibility-human", "visibility-human-child"], [], 100], { issues: [creationVisibilityTasks.find((issue) => issue.id === "visibility-child")!], hasMore: false });
return true;
});
return (
<div className="paperclip-story min-h-screen bg-background p-6 text-foreground">
<IssuesList
issues={creationVisibilityTasks}
agents={storybookAgents}
projects={storybookProjects}
viewStateKey={viewStateKey}
enableAgentCreatedVisibilityFilter
searchWithinLoadedIssues
rowPresentation="task"
toolbarPresentation="collection"
onUpdateIssue={() => undefined}
/>
</div>
);
}
const hidden: Story = {
name: "Agent-created tasks — hidden by default",
render: () => <CreationVisibilityStory />,
parameters: { docs: { description: { story: "Production task collection with simulated creation metadata and hierarchy reads. Agent and routine roots are hidden; agent subtasks and ancestors remain as context. Server participation and pagination are covered separately." } } },
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
await expect(await canvas.findByText("Human request")).toBeVisible();
await expect(canvas.getByText("Agent subtask")).toBeVisible();
await expect(canvas.getByText("Agent ancestor")).toBeVisible();
await expect(canvas.queryByText("Agent root task")).not.toBeInTheDocument();
await expect(canvas.queryByText("Scheduled routine run")).not.toBeInTheDocument();
await expect(canvas.queryByText("Chat channel task")).not.toBeInTheDocument();
},
};
const included: Story = {
name: "Agent-created tasks — explicit opt-in",
render: () => <CreationVisibilityStory included />,
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
await expect(await canvas.findByText("Agent root task")).toBeVisible();
await expect(canvas.getByText("Scheduled routine run")).toBeVisible();
await expect(canvas.getByText("Chat channel task")).toBeVisible();
},
};
const filter: Story = {
name: "Agent-created tasks — filter control",
render: () => <CreationVisibilityStory />,
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
await expect(await canvas.findByText("Human request")).toBeVisible();
canvas.getByTitle("Filter").click();
const page = within(canvasElement.ownerDocument.body);
await expect(await page.findByRole("checkbox", { name: /show agent-created tasks/ })).not.toBeChecked();
},
};
export const creationVisibilityStories = { hidden, included, filter };