Commit Graph
4 Commits
Author SHA1 Message Date
DottaandPaperclip 45dfb183b6 fix(ui): add undo action to inbox archive toast (#11220)
## Thinking Path

> - Paperclip helps operators supervise AI-agent work.
> - The Mine inbox keeps tasks that need an operator's attention in one
place.
> - Operators can archive a task from its detail page after they finish
triage.
> - That action is easy to select accidentally and did not offer
immediate recovery.
> - This pull request adds Undo to the archive success toast and keeps
inbox caches consistent.
> - The benefit is fast recovery without searching for or reopening the
task.

## Linked Issues or Issue Description

**What happened?**

Archiving a task from the Mine inbox removed it and showed a success
toast with no recovery action.

**Expected behavior**

The success toast should offer Undo. Selecting Undo should restore the
task through the existing unarchive API while preserving a consistent
inbox view.

**Steps to reproduce**

1. Open a task from the Mine inbox.
2. Select the archive action.
3. Observe that the task leaves the inbox and the success toast has no
Undo action.

**Paperclip version or commit**

Reproduced on `master` before this change.

**Deployment mode**

Local dev, built from source.

Related prior work: #9931 and #10668.

## What Changed

- Add an Undo action to the successful inbox archive toast.
- Optimistically restore the task in captured inbox query caches before
the unarchive request completes.
- Cancel in-flight inbox fetches and clear the local archive guard so
stale responses cannot hide the restored task.
- Reapply the archive guard and remove the cached task if the unarchive
request fails.
- Add regression tests for successful Undo, the in-flight cache race,
and failed Undo rollback behavior.

## Verification

- `pnpm exec vitest run ui/src/pages/IssueDetail.test.tsx
ui/src/lib/inboxArchiveCache.test.ts` — 51 tests passed on the final
head.
- `pnpm check:token-gates` — passed.
- `pnpm -r typecheck` — passed.
- `pnpm build` — passed.
- `pnpm test:run` — the general server and UI groups passed. One CLI
doctor assertion detected injected host AWS credentials and passed all 8
tests with those unrelated variables unset. A task-watchdog scheduler
test also passed all 18 tests in isolation after one full-suite timing
failure.

## Risks

Low risk. The change uses the existing unarchive endpoint and inbox
cache helpers. Undo failure returns the task to its archived state,
shows an error toast, and invalidates the inbox queries for server
reconciliation.

> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.

## Model Used

OpenAI Codex, model ID GPT-5. The service manages the context window.
Reasoning, tool use, and code execution were enabled.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-08-11 14:13:06 -04:00
DottaandPaperclip ec84eb7342 fix(ui): defer Inbox re-sort to attention boundaries (#10623)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - The Inbox lists work items by recent activity.
> - An archive changes activity data and can change the computed order.
> - The list can then move rows under the pointer during a fast archive
sequence.
> - The Inbox must keep its shown order while the operator is engaged.
> - This pull request adopts fresh order only at an idle, visibility, or
view-change boundary.
> - The benefit is a stable Inbox that still receives fresh data and new
items.

## Linked Issues or Issue Description

**What happened**

The Inbox re-sorts while an operator archives items quickly. An archive
can lower a parent group's activity time. Unrelated rows then move, and
the row under the pointer can change.

**Expected behavior**

Keep the shown order stable while the operator works in the Inbox.
Insert new items at their computed positions. Adopt a fresh order after
an idle period, after a long hidden-tab interval, or when the view
changes.

**Steps to reproduce**

1. Open the Inbox on the Mine tab with several items, including nested
items.
2. Archive several items quickly with the pointer or keyboard.
3. Observe rows move before the archive sequence is complete.

**Deployment mode**

Any deployment. This change affects only the web UI.

**Additional context**

This PR supersedes the closed subset PR #10621. It keeps the full change
in one review.

## What Changed

- Added an order-pin utility for sections, root rows, non-issue items,
and nested children.
- Kept archived rows in place for the existing five-second undo
interval.
- Added an attention-boundary hook for idle, visibility, and view-change
commits.
- Connected pointer, wheel, hover, keyboard, and archive interactions to
the idle boundary.
- Made idle commits repeat while the Inbox stays idle.
- Made view changes adopt the fresh order in the same render.
- Added unit and integration coverage for order pins and attention
boundaries.

## Verification

- `pnpm exec vitest run ui/src/hooks/useInboxSortAttention.test.tsx
ui/src/lib/inboxOrderPin.test.ts ui/src/pages/Inbox.test.tsx` — 33 tests
passed.
- `pnpm check:token-gates` — passed.
- `pnpm -r typecheck` — passed.
- `pnpm build` — passed.
- `pnpm test:run` — 3,429 tests passed, 2 skipped, and 1 unrelated
server test failed. The isolated failure expects `issue_commented` but
current master records `heartbeat.scheduling_suppressed` in
`plugin-orchestration-apis.test.ts`.

## Risks

- Low risk. The change is client-only and does not change the sort
algorithm.
- A bad pin can show an old order until the next boundary. The tests
cover repeated idle commits and immediate view changes.

> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.

## Model Used

- Anthropic Claude Opus 4.8 (`claude-opus-4-8`), extended thinking, tool
use, and code execution for the implementation.
- OpenAI Codex (`gpt-5`), reasoning, tool use, and code execution for PR
preparation and verification. The serving snapshot, context-window size,
and hidden reasoning configuration were not exposed.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-08-01 20:46:55 -05:00
DottaandPaperclip 59eee4829c fix(inbox): stop archived items from resurfacing (#9931)
## Thinking Path

> - Paperclip is the control plane operators use to coordinate AI-agent
companies and review work needing attention.
> - The Inbox is the operator-facing surface that aggregates tasks
requiring attention across server state and shared client polling.
> - Archiving a task optimistically removed it, but ordinary background
activity and stale polling responses could make it reappear seconds
later.
> - The server therefore needs to distinguish genuine user-attention
events from routine agent/system activity.
> - The client also needs a bounded local archive guard across every
Inbox query path while the server mutation and in-flight polls settle.
> - This pull request fixes both resurrection paths and adds
race-focused regression coverage.
> - The benefit is stable archive behavior without hiding a genuine
archive failure after reconciliation or reload.

## Linked Issues or Issue Description

### Pre-submission checklist

- [x] Searched existing open and closed issues and pull requests; no
duplicate implementation was found.
- [x] Reproduced on `master` before this branch.
- [x] Confirmed this is a Paperclip core bug, not adapter or provider
behavior.

### What happened?

Archiving an Inbox task hid it optimistically, then background refresh
activity could insert it back into the list seconds later.

### Expected behavior

A successfully archived task remains hidden during normal polling. A
genuine failed archive may become visible again after reconciliation or
reload.

### Steps to reproduce

1. Open Inbox with a visible task.
2. Archive the task.
3. Wait for shared polling or routine agent activity to refresh task
data.
4. Observe the archived task reappear without a hard page refresh.

### Paperclip version or commit

`master` before this branch.

### Deployment mode

Built from source using the local development application.

### Installation method

Built from source (`pnpm`).

### Agent adapter(s) involved

Not adapter-specific; this is a core Inbox bug.

### Database mode

Not database-mode-specific.

### Access context

Board (human operator).

### Additional context

The failure had independent server and client causes: routine activity
could resurface archived rows server-side, while stale shared-poll
responses could bypass optimistic client removal.

## What Changed

- Restrict server-side Inbox resurfacing to explicit user-attention
events rather than any issue activity write.
- Add a bounded client-side archive guard with confirmation, failure
restoration, and cache reconciliation behavior.
- Apply the guard to Inbox rendering, badge counts, optimistic cache
updates, and shared-poll result application.
- Classify the generic compact Inbox query so stale shared-poll data
cannot bypass the guard.
- Add server visibility-matrix tests and UI race-condition regression
tests.

## Verification

- `pnpm --filter @paperclipai/ui exec vitest run
src/hooks/useSharedPolling.test.ts src/lib/inboxArchiveCache.test.ts
src/pages/Inbox.test.tsx` — 25 passed.
- `pnpm --filter @paperclipai/server exec vitest run
src/__tests__/issues-service.test.ts` — 107 passed.
- Branch rebased cleanly onto current `origin/master` before push.

## Risks

- Low-to-moderate behavioral risk: resurfacing is intentionally
narrower, so the server tests cover human comments, mentions,
interactions, and status transitions that must still regain attention.
- The client guard is bounded and cleared on mutation failure, limiting
the risk of hiding a task whose archive did not persist.
- No schema, migration, public API, workflow, dependency-lock, or
visual-token changes.

> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.

## Model Used

- Anthropic Claude via Claude Code (`claude_local`; prior
implementation/review run, exact underlying model ID and context window
were not retained in the handoff metadata), with repository tool use and
test execution.
- OpenAI `gpt-5.5` via Codex CLI for final review repair and PR
preparation, with reasoning, repository editing, GitHub tooling, and
code execution.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and
linked/described the result above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change and contains no internal
Paperclip task identifier
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation where needed; no
documentation change is required for this bug fix
- [x] I have considered and documented risks above
- [x] All Paperclip-authored commits include the required co-author
trailer

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-07-21 08:13:14 -05:00
Dotta f40a8fbf1e [codex] Fix iOS inbox archive gestures (#9154)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - The board inbox is a high-frequency operator surface, especially on
mobile where row gestures are the primary way to dismiss handled work.
> - The existing swipe archive control shared one pending-state gate
across the inbox, so one archive request could make other inbox archive
controls feel stuck.
> - The touch handler also kept click suppression and archive timers
coupled too loosely, which made cancelled or partial iOS touch sequences
behave unpredictably.
> - This pull request keeps archive state per issue, makes swipe/cancel
cleanup explicit, and removes archived issues from every relevant inbox
query cache before navigation/refetch.
> - The benefit is that iOS users can archive from inbox/detail views
without the inbox getting into a weird pending or stale-cache state.

## Linked Issues or Issue Description

Bug report:

- Summary: On iOS/mobile, inbox swipe/archive interactions can leave the
inbox feeling stuck or stale after archiving a task.
- Expected: Archiving one inbox item should remove that item
optimistically, keep other archive controls usable, and recover cleanly
from partial or cancelled touch gestures.
- Actual: A pending archive globally disabled other archive controls,
touch cancellation could share the touch-end path, and issue-detail
archive navigation could happen before related inbox query caches were
cleaned up.
- Root cause: Archive pending state and inbox cache updates were handled
locally in multiple places instead of through reusable per-company cache
helpers, and the swipe component did not independently track live
offset, archive timers, and click-suppression timers.

## What Changed

- Split `SwipeToArchive` archive timeout handling from temporary click
suppression and added explicit touch-cancel/reset cleanup.
- Track swipe offset in a ref so commit threshold checks use the latest
touch position rather than potentially stale React state.
- Added shared inbox archive cache helpers for cancelling, snapshotting,
optimistic removal, rollback, and invalidation across inbox query
variants.
- Updated inbox archive mutations to disable only the row being archived
instead of every row while any archive request is pending.
- Updated issue-detail archive-from-inbox to remove the archived issue
from cached inbox variants before navigating back.
- Added focused tests for partial drags, cancelled touches, unmount
cleanup, per-row pending archive behavior, and detail-page cache removal
before navigation.

## Verification

- `pnpm exec vitest run ui/src/components/SwipeToArchive.test.tsx
ui/src/pages/Inbox.test.tsx ui/src/pages/IssueDetail.test.tsx`
  - 3 test files passed
  - 53 tests passed

## Risks

Low-to-medium risk. This changes mobile archive gesture state and
optimistic inbox cache handling, so the main risk is cache invalidation
missing an inbox query variant. The helper uses prefix-based React Query
APIs for the known inbox variants and still invalidates those variants
plus sidebar badges on settle.

> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.

## Model Used

OpenAI Codex, GPT-5 based coding agent, with repository tool use and
local command execution.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

Related PR search performed with `gh search prs "inbox archive iOS
swipe" --repo paperclipai/paperclip` and `gh search prs "SwipeToArchive"
--repo paperclipai/paperclip`; existing related work includes #1857 and
#1860, but no duplicate of this regression fix was found.
2026-07-07 07:22:42 -05:00