501 lines
31 KiB
Markdown
501 lines
31 KiB
Markdown
---
|
|
created: 2026-09-10
|
|
status: done
|
|
requirements:
|
|
- REQ-TASKS-THREADS-ACTIONS-001
|
|
- REQ-TASKS-THREADS-ACTIONS-002
|
|
- REQ-TASKS-THREADS-ACTIONS-003
|
|
- REQ-TASKS-THREADS-ACTIONS-004
|
|
system_design:
|
|
- ../../specs/tasks/system-design/threads-task-actions.md
|
|
legacy_specs: []
|
|
---
|
|
|
|
# Implementation Plan: Threads Task Actions
|
|
|
|
## Overview
|
|
|
|
Deliver the existing six task operations from each Threads header using shared
|
|
task actions, explicit target identity, and an inset phone drawer. Implement
|
|
the shared action boundary first, integrate desktop and deck recovery second,
|
|
complete phone interaction third, and publish accurate usage guidance last.
|
|
|
|
The `tasks` system owns this vertical capability because task identity,
|
|
eligibility, mutation results, and recovery are its contract. Existing UI
|
|
specifications continue to own the deck, shared header, saved-view query, and
|
|
viewport-driven session activity.
|
|
|
|
The user authorized implementation with "go for it" after the design-package
|
|
checkpoint. All four work orders are complete in the primary session. No
|
|
subagents or new platform tasks/sessions were used. Implementation and design
|
|
files were uncommitted at that implementation handoff; publication follows in
|
|
the user-requested Open PR workflow step.
|
|
|
|
## Parent prerequisite
|
|
|
|
This workspace started clean at `21f24eb8b` on
|
|
`feature/add-task-actions-to-548`. During this design turn, the parent committed
|
|
its completed mobile implementation as
|
|
`0b4253fa71ba0fe85188bff8cd27c2860425c516`
|
|
(`fix(ui): improve mobile threads and shared listing headers`) on
|
|
`feature/improve-mobile-threa-f2f`. The parent's working tree is clean.
|
|
Its committed `docs/plans/mobile-threads/plan.md` contains the execution results.
|
|
|
|
The branches diverge from `b7a71e64a`, so integration requires a normal merge,
|
|
not a fast-forward. The pinned parent commit was merged successfully at the
|
|
implementation start as `facf9aef7`, preserving this package. Its ancestry is verified and
|
|
the workspace dependencies are installed with the frozen lockfile.
|
|
|
|
Read-only inspection identified these parent integration points:
|
|
|
|
- `components/threads/mobile-thread-column-header.tsx`: two-line title picker,
|
|
Open task, status and session control.
|
|
- `components/threads/threads-board.tsx`: board-owned picker and
|
|
`renderHeader(activeMobileTaskId)` composition.
|
|
- `components/threads/use-mobile-thread-position.ts` and
|
|
`thread-viewport-geometry.ts`: scroll-derived position independent of chat
|
|
hydration; `use-thread-column-activation.ts` consumes it.
|
|
- `components/kanban/mobile-listing-*`: compact shared page header/menu, with
|
|
`mobile-picker-sheet.tsx` gaining `onCloseAutoFocus` support.
|
|
- `e2e/tests/task/mobile-threads-swipe.spec.ts` and its swipe helper:
|
|
held-touch midpoint, reversal, and paging evidence.
|
|
|
|
These paths are under `apps/web/`. The parent work orders and scoped guidance
|
|
were re-read after the normal merge and before feature edits. No individual
|
|
parent files were copied or recreated.
|
|
|
|
The separate **Choose Threads as default home view** subtask is not a dependency
|
|
and contributes no work to this package.
|
|
|
|
## Scope
|
|
|
|
### In scope
|
|
|
|
- Header-only desktop context entry and an always discoverable overflow button.
|
|
- Priority, workflow-step move, cross-workflow send, supported links, archive,
|
|
and confirmed delete through existing task behavior.
|
|
- Captured task/workspace identity, current eligibility, shared-state updates,
|
|
failure recovery, deterministic thread fallback, and surviving-trigger focus.
|
|
- One inset phone drawer, in-surface nested navigation, localization, desktop
|
|
density, touch sizing, containment, and unchanged native swiping.
|
|
- Focused TDD and desktop/mobile Playwright outcomes, rendered phone inspection,
|
|
and usage documentation.
|
|
|
|
### Out of scope
|
|
|
|
- Rebuilding the parent header, picker, inline pagination, or swipe logic.
|
|
- Default Home selection, saved-view behavior changes, or session management.
|
|
- New operations, bulk commands, providers, permissions, backend APIs, storage,
|
|
plugin SDK changes, feature flags, or broad UI menu migration.
|
|
|
|
## Technical approach
|
|
|
|
### Shared task action boundary
|
|
|
|
`hooks/use-task-menu-actions.ts` shares archive/delete lifecycle and successful
|
|
removal cleanup with the sidebar. `useTaskManagementFlow` owns captured identity
|
|
and current eligibility. `TaskManagementSurface` composes those owners with
|
|
`useTaskWorkflowMove`, `useUpdateTaskPriority` and existing link hooks. Preserve current menu option
|
|
derivation in `task-priority-context-menu.tsx`, `task-move-context-menu.tsx`, and
|
|
`task-switcher-link-menu.tsx`. Extract a focused
|
|
`components/task/task-management-menu.tsx` composition for the requested six
|
|
groups. Keep the existing full switcher menu as the default consumer.
|
|
|
|
Factor the existing destructive lifecycle glue into the shared task boundary
|
|
and consume it from an existing menu caller as well as Threads. Give
|
|
`useTaskRemoval` a caller-selected stay-on-listing behavior with its current
|
|
navigation as the default. Test that option against stale global task selection
|
|
and HTTP/WS ordering. Thread adapters contain rendering, target selection, and
|
|
deck focus, never API transport or task business rules.
|
|
|
|
The shared host captures `{ taskId, workspaceId }` on open and lives above the
|
|
column list. It resolves current task facts from the scoped snapshots by that
|
|
ID and retains the target through menu-to-dialog transitions. Reuse
|
|
`TaskArchiveConfirmation`, `TaskDeleteConfirmDialog`, and `SidebarLinkDialogs`.
|
|
Archive uses the shared preference and classification, including inline phone
|
|
confirmation when supported; complex confirmation and link dialogs replace the
|
|
menu before opening.
|
|
|
|
### Threads entry and recovery
|
|
|
|
Compose the shared host at `ThreadsBoard`, leaving `ThreadsPageClient` unchanged. Add a thin
|
|
`thread-task-actions.tsx` header adapter. Extend `TaskMenuButton` for a
|
|
controlled opener/ref while preserving existing callers. Restrict the context
|
|
trigger to the task header and exclude session controls, transcripts, and
|
|
editors.
|
|
|
|
Add `lib/threads/thread-selection-fallback.ts` with the pure
|
|
`resolveRemainingThreadId` algorithm. Use the parent's viewport position and
|
|
last committed admitted order for reconciliation. Preserve current surviving
|
|
tasks and their scroll offset; otherwise use successor, predecessor, first
|
|
newly admitted task, or the existing empty state. Shared lifecycle events drive
|
|
admission. Late responses cannot reset newer focus, resurrect removed columns,
|
|
or rewrite `/threads` to task detail.
|
|
|
|
### Phone composition
|
|
|
|
Add a shared task-domain `task-management-drawer.tsx` over the same option
|
|
sources and callbacks as desktop. Its page state contains root, priority,
|
|
steps, workflows, selected-workflow steps, and links. Use one Drawer instance,
|
|
one body scroller, visible Back, fixed header, `dvh` bounds, and safe-area
|
|
clearance. Compare the integrated parent versions of `mobile-menu-sheet.tsx`
|
|
and `mobile-picker-sheet.tsx`; do not reproduce the global nested-popper CSS.
|
|
|
|
Put the visible 44px overflow beside Open task in the parent's task header.
|
|
Keep the page topbar and inline swiper as shipped by the parent. Phone and
|
|
coarse-pointer entries use the drawer; fine-pointer controls retain compact
|
|
sizes. Cover 320px, 360px, 700px phone widths and a coarse-pointer tablet without
|
|
introducing a second horizontal gesture region.
|
|
|
|
## Tests
|
|
|
|
All code work orders use `/tdd`. Record the failing behavior before production
|
|
changes, then the passing targeted command. Proposed new test names describe
|
|
outcomes; adapt names only when the same outcome remains explicitly mapped.
|
|
|
|
| Test file and named cases | Acceptance coverage |
|
|
| --- | --- |
|
|
| `hooks/use-task-menu-actions.test.ts`, `use-task-management-flow.test.ts`, `lib/tasks/task-menu-target.test.ts`, `components/task/task-management-surface.test.tsx`: captured A, unresolved/cross-workspace targets, duplicate submits, removal failures/retry, obsolete link completion, filtered archive anchor | `002.1`-`002.6` |
|
|
| `components/task/task-management-menu.test.tsx`, existing link/confirmation tests and both browser suites: current-step eligibility/priority dispatch, ordered groups, provider choices, archive preference and deletion consent | `001.1`-`001.6`, `002.3`, `002.6` |
|
|
| Existing `use-task-removal.test.ts`, `use-task-actions.test.ts`, `use-task-workflow-move.test.ts`, `use-update-task-priority.test.ts`, link/confirmation tests | Existing mutation, cleanup, dirty-worktree, provider, preference, and error behavior under extraction |
|
|
| `lib/threads/thread-selection-fallback.test.ts`: seven survivor/successor/predecessor/replacement/empty cases | `003.1`-`003.3` |
|
|
| `components/threads/thread-task-actions.test.tsx`, `threads-board.test.tsx`, page/activation tests and both browser suites: named opener, removed-column focus, route preservation, native composer context, newer-menu focus, drafts and bounded activation | `002.1`, `002.2`, `002.5`, `003.1`-`003.6`, `004.1`, `004.6` |
|
|
| `components/task/task-management-drawer.test.tsx`, archive/surface tests and mobile browser suite: one nested surface, Back row focus, confirmation handoff and surviving focus | `001.1`-`001.6`, `004.2`-`004.7` |
|
|
|
|
Numeric shorthand in these tables expands to
|
|
`AC-TASKS-THREADS-ACTIONS-<number>`. Work-order frontmatter lists full IDs.
|
|
|
|
## E2E tests
|
|
|
|
New files are `apps/web/e2e/tests/task/threads-task-actions.spec.ts` in
|
|
`chromium` and `mobile-threads-task-actions.spec.ts` in `mobile-chrome`.
|
|
Extract common seed/action helpers to sibling `threads-task-actions-helpers.ts`.
|
|
Follow `threads-view.spec.ts`: run a real mock-agent turn to establish a primary
|
|
session, or use the existing eligible review/clarification fixture. Arbitrary
|
|
seeded RUNNING sessions are not primary and cannot prove the feature.
|
|
|
|
Each action row below is exercised on **both** projects. The action fixtures
|
|
use unrelated tasks A and B with real primary sessions. Captured-flow tests and
|
|
the existing session-switching regressions also protect global and sibling
|
|
session selection. Check visible results, query persistence, then reload and
|
|
verify the task metadata remains correct.
|
|
|
|
| Action / browser test | Required outcome | AC |
|
|
| --- | --- | --- |
|
|
| `changes the opened task priority` | Submenu current value changes for A, B stays unchanged; saved-view filtering can remove A | `001.2`, `002.2`, `002.4`, `003.1`-`003.4` |
|
|
| `moves the opened task to a workflow step` | A reaches the selected step, existing current/auto-start markers match, membership recovery works | `001.3`, `002.4`, `003.1`-`003.5` |
|
|
| `sends the opened task to another workflow` | Select workflow then step; A persists there, no-step workflow is disabled, route and B are preserved | `001.3`, `002.2`, `002.4`, `003.1`-`003.5` |
|
|
| `links the opened task through the existing form` | Supported provider rows use existing availability; submit a mocked GitHub issue/PR link to A, verify association and B unchanged | `001.4`, `002.2`-`002.5`, `004.3` |
|
|
| `archives the opened task` | Preference on: cancel causes no request, then confirm succeeds; preference off: direct non-cascade archive; survivor/empty state is correct | `001.5`, `002.4`, `003.1`-`003.5` |
|
|
| `deletes only the confirmed task` | Destructive row follows separator; cancel preserves task/sessions; required consent precedes one delete; survivor/empty state is correct | `001.1`, `001.6`, `002.2`, `002.6`, `003.1`-`003.5` |
|
|
|
|
Cross-action scenarios also run in the owning project:
|
|
|
|
| Scenario | Evidence | AC |
|
|
| --- | --- | --- |
|
|
| Desktop context and keyboard overflow equivalence | Same six groups; Enter/Space and keyboard submenu traversal work; chat/editor context stays native | `001.1`, `004.1`, `004.6` |
|
|
| Selection changes while flow is open | A remains target after independent selection/WS changes, B and its chosen session stay unchanged | `002.1`-`002.3`, `002.5` |
|
|
| Rejection and retry | Inject a move or archive failure and invalid link, assert error plus unchanged confirmed state; replay a later valid UI action | `002.5`, `003.4` |
|
|
| Nested dismissal and surface handoff | Back/Escape/outside at root and nested pages; cancelled archive/delete/link; original, replaced, removed, and offscreen trigger focus | `001.5`, `001.6`, `004.3`, `004.6` |
|
|
| Narrow phone, long lists and native swipe | Bound every active page/dialog; assert 44px hitboxes, hit testing, one scroller, safe-area clearance, and no document overflow; swipe before and after menu use | `003.6`, `004.2`-`004.7` |
|
|
|
|
For phone identity testing, use live updates or an independent client while the
|
|
modal is open; do not force clicks through an inert backdrop. Exercise actual
|
|
touch swipes with the parent's helper after dismissal. Use mocked providers
|
|
and isolated E2E storage, not production credentials or a developer instance.
|
|
Component tests cover all first-party and registered plugin choice dispatch;
|
|
the browser link outcome uses supported existing integration fixtures.
|
|
|
|
Managed runs build current production assets and use one worker per shard.
|
|
Run desktop and mobile sequentially with one project per command and retries
|
|
disabled. Use causal HTTP/WS waits or persisted-state polling, never sleeps.
|
|
Restore any modified user settings in `afterEach`.
|
|
|
|
## Work orders
|
|
|
|
- [x] [Task 01: Share the task action flow](task-01-shared-task-action-flow.md)
|
|
- [x] [Task 02: Integrate desktop Threads task actions](task-02-desktop-threads-actions.md)
|
|
- [x] [Task 03: Make task choices touch accessible](task-03-phone-task-actions.md)
|
|
- [x] [Task 04: Document Threads task actions](task-04-document-task-actions.md)
|
|
|
|
Execute 01 → 02 → 03 → 04 sequentially after the parent prerequisite. No work
|
|
order is parallel-safe because menu types, action state, and test helpers overlap.
|
|
Each code work order owns its RED/GREEN and exact verification commands.
|
|
|
|
## Verification results
|
|
|
|
- Parent `0b4253fa7` merged as `facf9aef7`; ancestry verified. Frozen-lockfile
|
|
install, `make -C apps/backend build`, and `pnpm run build:e2e` passed.
|
|
- Focused unit/component checks: **217 passed in 25 files**, two workers.
|
|
- Desktop: **6 new tests passed** with retries disabled. All **17 existing**
|
|
Threads/workflow regressions passed. A first combined run found a test-driver
|
|
submenu pointer-grace issue; explicit submenu activation fixed the driver,
|
|
and the final six-test rerun passed against the same production build.
|
|
- Mobile: the **29-test suite passed**, including all five new tests and 24
|
|
parent/shared-menu cases, with retries disabled. Test discovery
|
|
confirmed all 29 cases; the final run reported no failed tests.
|
|
- Typecheck, affected-file ESLint with zero warnings, formatting, `i18n:check`
|
|
and `i18n:ratchet` passed. All copy reuses existing keys; no locale generation
|
|
or catalog changes were necessary. Existing orphan-key warnings are unchanged.
|
|
- New 320px/360px phone header, root/deep drawer and delete-confirmation renders
|
|
inspected. The menu is inset, long labels remain bounded, the last step is
|
|
reachable, and the original compact topbar/swiper remain intact. Task 03
|
|
records image paths and geometric assertions.
|
|
- Public-doc validator tests passed; the live validator passed for 46 pages.
|
|
- `python3 scripts/lint-spec-files.test.py`: passed, 30 tests.
|
|
- `python3 scripts/lint-spec-files.py --all`: passed.
|
|
- `git diff --check`: passed.
|
|
- Package link/traceability check: all seven new artifacts resolve their links;
|
|
all 25 acceptance criteria are assigned to work orders.
|
|
|
|
The final combined unit command, from `apps/web`, was:
|
|
|
|
```bash
|
|
pnpm exec vitest run --maxWorkers=2 \
|
|
hooks/use-task-menu-actions.test.ts hooks/use-task-management-flow.test.ts \
|
|
hooks/use-task-removal.test.ts hooks/use-task-removal-session-loading.test.ts \
|
|
hooks/use-task-actions.test.ts hooks/use-task-workflow-move.test.ts \
|
|
hooks/use-update-task-priority.test.ts lib/tasks/task-menu-target.test.ts \
|
|
lib/threads/thread-selection-fallback.test.ts \
|
|
components/task/task-management-menu.test.tsx \
|
|
components/task/task-management-surface.test.tsx \
|
|
components/task/task-management-drawer.test.tsx \
|
|
components/task/task-switcher-context-menu.test.tsx \
|
|
components/task/task-archive-confirmation.test.tsx \
|
|
components/task/task-delete-confirm-dialog.test.tsx \
|
|
components/task/task-session-sidebar-link-actions.test.ts \
|
|
components/task/task-session-sidebar-move.test.ts \
|
|
components/threads/thread-task-actions.test.tsx \
|
|
components/threads/threads-board.test.tsx \
|
|
components/threads/thread-column-activation.test.tsx \
|
|
components/kanban/kanban-header-mobile.test.tsx \
|
|
app/threads/threads-page-client.test.tsx lib/threads/stable-order.test.ts \
|
|
lib/threads/thread-view-query.test.ts \
|
|
components/threads/thread-session-switcher.test.tsx
|
|
```
|
|
|
|
Managed E2E commands used `--host --no-build` after explicitly building current
|
|
production assets. They ran sequentially with one worker, against isolated
|
|
mock-agent/provider fixtures. Task 02 and Task 03 record the exact commands.
|
|
|
|
Design reference inspection used the parent's existing rendered 360px captures
|
|
`/tmp/kandev-mobile-threads-PuEDK5/mobile-shared-threads-360.png` and
|
|
`mobile-shared-threads-menu-360.png`. They show the compact inline topbar, the
|
|
existing task header, and inset menu geometry. They are historical parent
|
|
evidence only; they do not verify the proposed task menu.
|
|
|
|
## Header alignment follow-up (2026-09-10)
|
|
|
|
Completed the user's screenshot-driven styling correction within the existing
|
|
package. Desktop Open task and overflow now share a vertical center; mobile
|
|
picker, Open task and overflow have equal 48px center-to-center spacing. Title
|
|
placement, header height, touch targets and task/swipe behavior are preserved.
|
|
|
|
Both new bounding-box assertions failed on the previous build (desktop 2px
|
|
offset; mobile 38px versus 48px gaps) and passed after the fresh E2E build. The
|
|
focused desktop context/keyboard and mobile long-label/nested/swipe tests each
|
|
passed with one worker and no retries. Typecheck, affected-file ESLint,
|
|
formatting, specification lint and whitespace checks passed. Task 02 and Task
|
|
03 contain exact commands and evidence.
|
|
|
|
Fresh dark desktop and 360px touch-phone rendering was inspected in the existing
|
|
isolated Tailscale preview. Screenshots are retained under
|
|
`/tmp/kandev-threads-seed-scLDiX/{desktop,phone}-header-{before,after}.png`.
|
|
Only its generated static assets/index were refreshed; prior assets/index are
|
|
retained, and its processes and user test data were not restarted or changed.
|
|
The preview remains on :19468, with the same identity-checked shutdown command.
|
|
The main :9998 instance was not queried, modified or stopped.
|
|
|
|
After approving the visual correction, the user requested shutdown. The
|
|
identity-checked sandbox wrapper stopped its backend and agent descendants;
|
|
ports 19468, 59468 and 59568-59667 no longer listen. Disposable data and captures
|
|
are retained. The main :9998 runtime was not stopped or reconfigured.
|
|
|
|
## Ready PR integration (2026-09-10)
|
|
|
|
The user requested a concise, template-based ready PR. Feature commit
|
|
`046832b6d` passed the normal commit hooks. Parent PR #3570 remained open;
|
|
its reviewed tip `8b508fdb307f4449edc2c2fbe23a5dad4d87a54e` was integrated
|
|
through merge `4c68ac5c5`. The PR targets `feature/improve-mobile-threa-f2f`
|
|
so its diff contains only this follow-up, not the parent's changes.
|
|
|
|
The combined board exceeded the function-size lint by one line. Extracting
|
|
its existing picker-focus helper preserved behavior; all 26 board tests
|
|
passed before and after extraction, followed by successful normal merge
|
|
hooks. No parent behavior or unrelated main-branch changes were replaced.
|
|
|
|
Integrated validation passed: 219 focused unit/component tests in 27 files
|
|
(including extracted listing-removal cases and parent mobile-position
|
|
coverage), typecheck, i18n checks and ratchet, public-doc validator tests and
|
|
all 46 published pages, 36 specification-linter tests, full specification
|
|
lint, and whitespace checks.
|
|
|
|
A fresh managed backend/web build produced synthetic-data PR screenshots
|
|
at 1280x850 desktop and 360x780 touch-phone sizes. The desktop root menu,
|
|
phone root drawer and nested workflow-step drawer were inspected and PNG
|
|
compressed. The ignored `.pr-assets/manifest.json` maps all three files;
|
|
the disposable capture spec was removed. The manual Tailscale preview
|
|
remained stopped throughout.
|
|
|
|
The first combined build/browser invocation was terminated with SIGTERM
|
|
(exit 143) after 19 passing tests, including the cross-device capture; it
|
|
reported no assertion failure. Its processes had exited before the final
|
|
regression runs reused the same fresh build.
|
|
|
|
The final desktop run passed all 23 tests with one worker and no retries:
|
|
|
|
```sh
|
|
cd apps/web
|
|
pnpm e2e:run --host --no-build --project chromium tests/task/threads-task-actions.spec.ts tests/task/threads-view.spec.ts tests/kanban/cross-workflow-task-move.spec.ts -- --retries=0
|
|
```
|
|
|
|
Both bounded mobile runs also passed, with one worker and no retries:
|
|
14 Threads/task-action/swipe tests and 17 shared-sidebar regressions.
|
|
Together, final browser verification covers 23 desktop and 31 mobile cases.
|
|
|
|
```sh
|
|
pnpm e2e:run --host --no-build --project mobile-chrome tests/task/mobile-threads-task-actions.spec.ts tests/task/mobile-threads-view.spec.ts tests/task/mobile-threads-swipe.spec.ts -- --retries=0
|
|
pnpm e2e:run --host --no-build --project mobile-chrome tests/task/mobile-sidebar-task-actions.spec.ts -- --retries=0
|
|
```
|
|
|
|
## PR feedback correction (2026-09-10)
|
|
|
|
The Back and Close drawer controls now use the repository-required pointer
|
|
cursor. The existing mobile regression reproduced the prior `default` cursor
|
|
before the two class changes. A fresh managed build passed all five mobile
|
|
task-action cases; the focused drawer/surface/header component checks passed
|
|
five tests, with ESLint and typecheck also passing. The 360px nested drawer
|
|
was inspected. Task 03 records the exact commands and RED/GREEN evidence.
|
|
|
|
Reviewer follow-up also reproduced and fixed same-workflow moves being rejected
|
|
when that workflow is hidden, loaded active steps being shadowed by a placeholder
|
|
snapshot, and archived targets remaining eligible in a stale snapshot. The
|
|
GitLab link row again retains its pre-existing 48px phone minimum. Regression
|
|
tests failed for each case before the scoped fixes. The focused suite passed
|
|
64 tests in ten files; the fresh mobile build passed all five Threads action
|
|
tests plus the GitLab linking regression (six tests, one worker, no retries).
|
|
The six desktop action tests passed after the behavior-preserving cleanup.
|
|
|
|
Claude's suggestions removed ineffective props memoization and redundant
|
|
workflow filtering, named the empty-board dependency, and clarified the existing
|
|
error-toast ownership. Cubic's postfix-important warning was not reproducible:
|
|
the generated CSS includes important width/height for `size-11!`, and the phone
|
|
regression checks real 44px targets through the 820px coarse-pointer viewport.
|
|
CodeRabbit's documentation nit was valid; the how-to now describes the existing
|
|
first-new-thread fallback before the genuinely empty state. These corrections
|
|
implement the existing requirements and design, without a new contract or copy.
|
|
|
|
Parent PR #3570 merged while review was in progress, retargeting this PR to
|
|
`main`. Integration with `5ffe8818773bd7c7bda548f3086b305b9b618d55` preserves
|
|
the landed control-sizing primitives, shared archive/delete switching helper,
|
|
and task-detail dialog focus refs alongside Threads' listing-only removal and
|
|
custom focus recovery. Two compatibility tests cover default-ref restoration
|
|
and the Threads override. The integrated unit/component suite passed 252 tests
|
|
in 29 files, and the fresh managed desktop build passed 27 browser tests with
|
|
one worker and no retries, including shared task-detail/preview outcomes.
|
|
The integrated phone run passed 15 cases with one worker and no retries:
|
|
Threads actions, parent view/picker/swipe behavior, and the shared GitLab link
|
|
row. It reused that freshly built backend/web pair.
|
|
Typecheck, affected-file ESLint, locale validation, public-doc validation,
|
|
specification lint and harness checks passed. Earlier stacked-base results
|
|
above remain historical.
|
|
Remote exact-head CI/review confirmation remains part of the ongoing fixup,
|
|
not a completed claim in this local verification record.
|
|
|
|
### CI archive concurrency correction (2026-09-10)
|
|
|
|
E2E run `34527249627`, shard job `103043769179`, reproduced a shared-sidebar
|
|
regression: after optimistic navigation from A to B, archiving B while A's
|
|
request was pending was silently rejected by the shared global single-flight
|
|
guard. The trace contained only A's archive request. The unchanged
|
|
`archive-task-redirect.spec.ts` reproduced the same last-task URL failure
|
|
locally with retries disabled. Its dependent report and final gate failed from
|
|
that one unexpected test; no additional failed leaf was reported.
|
|
|
|
Four held-request unit cases failed before the fix for archive and delete,
|
|
covering concurrent A/B requests, same-task duplicate rejection, out-of-order
|
|
completion, and A's failure/retry while B remains pending. The shared removal
|
|
owner now guards pending task IDs independently and retains the first pending
|
|
ID for existing busy consumers. Navigation, confirmation, error feedback and
|
|
Threads' listing-only cleanup still belong to their existing owners.
|
|
|
|
After the fix, the focused unit/component checks passed 141 tests in 17 files,
|
|
including those four regressions. Typecheck, zero-warning affected-file ESLint
|
|
and locale validation passed. After `pnpm run build:e2e`, these managed browser
|
|
runs passed with one worker and no retries: eight desktop cases and nine phone
|
|
cases, including all six actions, cancellation, nested containment and swipe
|
|
coexistence.
|
|
|
|
```sh
|
|
cd apps/web
|
|
pnpm exec vitest run --maxWorkers=2 hooks/use-task-menu-actions.test.ts hooks/use-task-actions.test.ts hooks/use-task-actions-menu-move-targets.test.tsx hooks/use-task-removal.test.ts hooks/use-task-removal-listing.test.ts hooks/use-task-removal-session-loading.test.ts hooks/use-task-workflow-move.test.ts hooks/use-task-management-flow.test.ts components/task/task-management-surface.test.tsx components/task/task-archive-confirmation.test.tsx components/task/task-delete-confirm-dialog.test.tsx components/task/task-session-sidebar-link-actions.test.ts components/task/task-session-sidebar-move.test.ts components/task/task-session-sidebar-selection.test.ts components/threads/thread-task-actions.test.tsx components/threads/threads-board.test.tsx
|
|
pnpm exec vitest run --maxWorkers=2 lib/tasks/task-menu-target.test.ts
|
|
pnpm e2e:run --host --no-build --project chromium tests/task/archive-task-redirect.spec.ts tests/task/threads-task-actions.spec.ts -- --retries=0
|
|
pnpm e2e:run --host --no-build --project mobile-chrome tests/task/mobile-threads-task-actions.spec.ts tests/task/mobile-threads-swipe.spec.ts tests/task/mobile-archive-task-redirect.spec.ts -- --retries=0
|
|
```
|
|
|
|
CodeRabbit's valid follow-up suggestions also corrected the work-order path,
|
|
strengthened inline confirmation containment with an awaited scoped query,
|
|
and preserved all six link-handler keys with compile-time checking. The
|
|
suggested Threads-agent contract is not a repository requirement: the scoped
|
|
guide documents component ownership, not a separate agent. The optional
|
|
layout-effect optimization is not applied; its effect reads `orderedIds` and
|
|
refreshes geometry/focus bookkeeping, and no lint suppression is introduced.
|
|
These changes preserve the approved contract and rendered layout. Remote CI
|
|
and current-head review are rechecked after pushing, not assumed from local
|
|
results.
|
|
|
|
## Main integration follow-up (2026-09-11)
|
|
|
|
Resolved conflicts with the landed task-removal navigation coordinator in the
|
|
sidebar, action wrappers and removal hook. Both shared menu operations now use
|
|
that coordinator. Threads records pending targets without a detail departure,
|
|
so remembered global selection cannot trigger destination loading or failure
|
|
recovery navigation. Default detail/preview protection, cascade cleanup,
|
|
per-task duplicate guards and localized success/error feedback remain shared.
|
|
|
|
Four added integration cases cover archive/delete pending ownership, successful
|
|
cleanup and failed removal with a remembered active session. Three failed on
|
|
the initial mechanical merge: archive acquired a detail departure, deletion
|
|
did not register a coordinated operation, and failed archive redirected to the
|
|
overview. The focused checks passed after the compatibility fixes: 201 tests
|
|
across 25 files, including the landed coordinator and all existing menu/Threads
|
|
regressions. The new cases can be rerun from `apps/web` with:
|
|
|
|
```sh
|
|
pnpm exec vitest run --maxWorkers=2 hooks/use-task-menu-actions.test.ts hooks/use-task-removal-listing.test.ts hooks/use-task-actions.test.ts hooks/use-task-removal-coordinator.test.ts hooks/use-task-removal.test.ts hooks/use-task-removal-session-loading.test.ts hooks/use-task-management-flow.test.ts components/task/task-session-sidebar-selection.test.ts lib/state/task-removal.test.ts
|
|
pnpm exec vitest run --maxWorkers=2 hooks/use-task-workflow-move.test.ts hooks/use-update-task-priority.test.ts hooks/use-task-crud.test.ts hooks/use-sidebar-multi-select.test.ts components/task/task-management-menu.test.tsx components/task/task-management-surface.test.tsx components/task/task-management-drawer.test.tsx components/task/task-switcher-context-menu.test.tsx components/task/task-session-sidebar-link-actions.test.ts components/task/task-session-sidebar-move.test.ts components/task/task-archive-confirmation.test.tsx components/task/task-delete-confirm-dialog.test.tsx components/threads/thread-task-actions.test.tsx components/threads/threads-board.test.tsx lib/tasks/task-menu-target.test.ts lib/threads/thread-selection-fallback.test.ts
|
|
```
|
|
|
|
Typecheck, affected-file ESLint, formatting, locale checks, specification lint,
|
|
harness validation and public-doc validation passed. The incoming canvas fixture required only `gofmt`
|
|
normalization; its whitespace-insensitive diff against main is empty.
|
|
The system design now names the coordinator. Public documentation and the
|
|
existing static menu screenshots still describe the same user workflow and
|
|
layout. Managed browser verification passed all 10 desktop and seven phone
|
|
cases, with one worker and no retries. The first command rebuilt the backend,
|
|
web assets and packaged plugin fixture; the second reused that same build.
|
|
Fresh 320px menu and 360px confirmation captures were inspected for containment.
|
|
|
|
```sh
|
|
pnpm e2e:run --host --project chromium tests/task/threads-task-actions.spec.ts tests/task/archive-task-redirect.spec.ts tests/task/delete-task-redirect.spec.ts -- --retries=0
|
|
pnpm e2e:run --host --no-build --project mobile-chrome tests/task/mobile-threads-task-actions.spec.ts tests/task/mobile-archive-task-redirect.spec.ts tests/task/mobile-delete-task-redirect.spec.ts -- --retries=0
|
|
```
|
|
|
|
[CI follow-up](ci-launcher-signal-readiness.md) records the launcher fixture race exposed after pushing.
|
|
|
|
## Risks
|
|
|
|
- Parent files and archive-confirmation work can change before integration;
|
|
re-read those owners before implementation and preserve their final changes.
|
|
- `ActiveThread` lacks priority, step identity, executor and repository details;
|
|
a lossy task projection would silently alter eligibility or consent.
|
|
- Sidebar removal helpers can navigate to `/t/:id` or Home using remembered
|
|
global selection; the shared listing option must suppress that side effect.
|
|
- Menu unmount, nested overlay handoff, late responses, and filter removal can
|
|
invalidate trigger refs or retarget callbacks unless identity and focus have
|
|
explicit lifetimes.
|
|
- The below-640px global menu styles do not cover every phone/coarse-pointer
|
|
case and position nested portals independently; scoped drawer navigation and
|
|
rendered containment tests are required.
|