mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-11-05 12:29:37 +01:00
9fb06afbfab284f8dcecf6ebc3dee3bfcda4e09d
4
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
b40e6edaea |
perf(inbox): combine startup reads and reduce refetch pressure (#18790)
## Thinking Path > - Paperclip helps people manage AI agents and their work. > - Mine shows the work and failures that need the viewing user's attention. > - A reload waits for account access, task rows, parent captions and failure state. > - Those reads form several browser request stages before useful rows appear. > - Live invalidations can also restart the same task-list request more than once. > - This change supplies startup data together and removes redundant refresh work. > - It preserves current authority, failure presentation, archive state and row stability. ## Linked Issues or Issue Description Refs #18645. Related: #18642. This change implements the read-receipt behavior independently on current master. It does not use that PR's branch or patch. **What happened?** Mine starts its primary request after the session, company and board-access reads. It then requests parent captions and rich failure context. Four observed loads spent another 0.45–0.70 seconds after the primary rows arrived. One slower load waited 1.71 seconds for parent context. The same run observed two HTTP 429 responses. These timings identify request waits; they do not attribute the delay to SQL or Node CPU. Read receipts also invalidate general task collections and dashboards. Overlapping parent and child invalidations can start two requests and abort the first. **Expected behavior** The initial page should use one account-safe startup projection and one complete Mine response. A read receipt should refresh the affected viewer's inbox state. Each invalidation batch should refresh a covered query once. Required captions and current failure state must be ready before first reveal. Existing rows should remain usable during a transient refresh error. **Steps to reproduce** 1. Open a populated Mine inbox with parent tasks outside the visible index and a current failed run. 2. Reload with browser HTTP cache retained and application query state empty. 3. Inspect the session, company, board access, task-index and context request sequence. 4. Open or mark a task read and inspect the unrelated collection refetches. **Paperclip version or commit** Baseline: `44a9a043b80c18314d8dd89556f444dae696d3d6`. **Deployment mode** Authenticated board UI. Local proof uses the real APIs and database with a synthetic session resolver. No hosted candidate deployment is claimed. ## What Changed - Add optional, same-user `boardBootstrap` data to the existing session response. Seed account-keyed company and board-access reads from it. Keep ordinary endpoint reads for fallback, retry and live reconciliation. A returning account cannot reuse revoked cached access. Cache collection and later real refetches remain effective. - Add the board-only Mine snapshot endpoint. Reuse the canonical issue selector, private-task filtering, run-read decisions, secret redaction and interruption/recovery presentation. Assemble the fixed 100-task page, parent captions and bounded 200-run failure window on the server. Start independent reads together. Optional source errors keep successful task rows usable. - Keep array-shaped source caches for archive and undo. Key Mine source, context and reveal state by account. Validate the response's user stamp before committing it. Remove array-only cross-tab Mine broadcasts, which cannot carry its paired failure context. The server retains authenticated in-flight coalescing. - Scope read-receipt invalidation to the affected viewer's inbox, badges and chat unread state. Keep company and task audit views fresh. Preserve genuine task mutations, run updates and subscription-gap reconciliation. - Remove covered scalar-prefix invalidations within a batch. Preserve predicates, exact matches and different query/refetch constraints. A later event can still refresh again. - Retire Mine in-flight reuse after local company activity or run lifecycle changes. A post-archive read starts fresh. Old work keeps its admission slot until it settles, even if every HTTP client aborts. The eight-compute limit stays in place. - Add API, component and browser regressions. Extend the production timing harness with matching API/UI artifact receipts, retained-cache reloads, request status counts, layout checks and optional controlled network latency. Update API and verification documentation. ## Verification - Full `pnpm -r typecheck` passes. - Full `pnpm build` passes. - Token gates, map checks and diff whitespace checks pass. - 72 Inbox component tests pass. Startup-specific checks pass, including account switching, revoked cached access, malformed/absent bootstrap data and cache collection. The canonical authenticated bootstrap route also passes against real PostgreSQL. - Six real PostgreSQL Mine route cases pass, including full equivalence with legacy authorized projections, privacy, fixed bounds, membership revocation, coalescing, archive freshness and aborted-client admission. Four focused legacy coordinator controls pass. Six assembly tests pass. - Refetch and invalidation regressions pass. Meaningful pre-fix tests observed two request starts and one abort for overlapping invalidations; the fix produces one start and no abort. The archive race test observed the post-archive GET joining the old body before the fix. - All 11 existing startup browser checks pass, including Tasks/Mine code loading, desktop/mobile bounds, non-streamlined Coordinator, task navigation, failed preloading and Back position. The nine focused startup, fallback, partial-source error, rate-limit recovery, archive/undo and geometry cases also pass. The 429 cases use the inherited retry window. Archive and keyboard undo are corroborated through the real API and reload. Authentication and failure fault injection in these cases are explicitly simulated. - Matched production before/after timings are complete. Full aggregate Vitest coverage is left to CI. At 15:15 UTC, the final-head runner gate and `review` workflow pass. The 45 build/test/policy jobs are queued; the Build job has no `ubuntu-latest` runner assigned and has executed no steps, so remote aggregate results remain unverified. Paperclip Review and Superagent Security Scan are in progress. Superseded runs for this PR were cancelled. No current-head check has reported a failure; the CI checklist remains open. The remaining step is runner allocation and completion of those external checks; persistent queueing needs the repository CI owner's attention. - Greptile completed on final head `ecde295565309275c4f2fae903caf6892f1eaafd` at 5/5. The map-scope finding is fixed and resolved; there are no open review threads. ### Matched browser timings Five alternating baseline/candidate pairs per network scenario, measured serially in headful Chrome 156.0.8078.80 on Apple silicon with Node 24.22.2 and a 1440×900 viewport. Both production UIs use their matching real API revision against one fixed disposable PostgreSQL fixture: 34 tasks, 31 visible task rows, one paused agent and one terminal failure. No active agent/provider work. HTTP cache is retained; each initial sample reloads the document and clears application query state. Warm navigation and Back retain query state. CPU and throughput are native. The 100ms scenario uses CDP minimum request-to-response-header latency without request interception. It is a controlled request-dependency experiment, not a staging reproduction. Values are median milliseconds with min–max in parentheses. Paired saving is baseline minus candidate for each alternating pair; its median differs from the difference of arm medians. Positive saving favors the candidate. | Network / journey | Baseline | Candidate | Median paired saving | | --- | ---: | ---: | ---: | | Native / initial rows | 187.6 (128.9–208.5) | 191.7 (130.3–210.9) | −23.3 | | Native / Recent → Mine | 100.17 (99.90–101.87) | 100.07 (99.88–101.37) | −0.16 | | Native / task → Back | 70.45 (56.63–72.02) | 66.64 (56.52–67.71) | +4.94 | | 100ms / initial rows | 930.3 (914.1–1015.7) | 799.0 (697.1–826.0) | +211.8 | | 100ms / Recent → Mine | 100.09 (97.73–100.16) | 100.18 (96.65–100.98) | −0.02 | | 100ms / task → Back | 74.97 (62.77–75.82) | 75.47 (61.51–76.19) | +0.35 | The controlled-latency initial pairs all improve, saving 108.3–217.0ms. Native initial pairs have mixed signs (−67.5 to +78.1ms), so they establish no reliable native page-speed improvement. Warm and Back timings are effectively unchanged. Median primary-request start is 110.4→135.2ms natively and 497.8→480.9ms with 100ms latency; these runs do not establish a large startup-only timing gain. API requests through the two-second post-reveal window fall from median 32 (32–37) to 27 (25–28) natively, and 37 (33–38) to 30 (25–32) with 100ms latency. All 20 samples preserve the same ordered 31 task links, first-row DOM identity and geometry. All recorded API responses are HTTP 200; zero unfinished requests, 429s or JavaScript errors. Lower 429 incidence on staging remains unproven. Measured source: baseline `44a9a043b80c18314d8dd89556f444dae696d3d6`, candidate `4c12b2ef0ecf0754676e99bd6b9399e84408646c`. Final head `ecde295565309275c4f2fae903caf6892f1eaafd` changes only two feature-map files and existing browser test expectations since that measured candidate; production executable inputs are identical to the measured candidate. Asset hashes, API health revision receipts and every raw sample were retained. These results do not claim hosted-page improvement or deployment of this PR. ## Risks - Startup enrichment adds work to the session read. Failure of this optional projection falls back to the ordinary company and access endpoints. It does not invalidate a valid session or replace per-request server authorization. - Account changes, stale cache entries and same-company navigation can expose old presentation data. Account keys, principal stamps, reveal scopes and canonical bootstrap replacement have dedicated negative cases. Permission failures hide cached task rows; transient network, 429 and 5xx failures preserve them. - Current failure state can differ from the historical failed run. The snapshot uses the existing canonical rich projection and verified missing-ID coverage. Partial context failures retain an explicit retry path. - Mutation retirement follows events delivered to the current server process. This adds no cross-replica invalidation protocol or distributed read-after-write guarantee. - New UI assets require the matching API. Older UI/session consumers retain their existing response and endpoint behavior. There is no database migration, provider call or deployment change. ## Model Used OpenAI Codex, based on GPT-6, with reasoning, code execution, browser automation and delegated source review. The exact runtime model ID and context-window size are not exposed by this session. ## 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 - [ ] 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> |
||
|
|
1f8f2e195f |
perf(ui): reuse parent metadata when loading the inbox (#18645)
## Thinking Path > - Paperclip helps people manage AI agents and their work. > - The Mine inbox combines task rows with approval and failure items. > - It waits for parent captions before it reveals the initial list. > - It fetched rich diagnostics for every parent, including parents already in the task index. > - Parent captions only use fields that the index already provides. > - This change reuses loaded parents and fetches missing parent metadata through the index view. > - Failure items keep their rich interruption data and the initial reveal boundary stays in place. ## Linked Issues or Issue Description **What existing behavior does this improve?** The initial load of Mine and other inbox views that need parent task captions. **Subsystem affected** `ui/` collection reads. The API contract and database schema stay the same. **Current behavior** The inbox fetches all parent and failed-run task IDs with `view=rows` after the primary task request. This adds active-run, blocker, review, interruption and recovery work to the reveal path. The observed hosted case fetched four parents. One was already in the 31-row task index. The other three were completed parents. The serial context response took 1.0–2.9 seconds during the diagnostic reloads. **Proposed behavior** Reuse parents from the selected source index. Fetch missing parents with `view=index`. Keep `view=rows` for every failed-run task, including overlaps with parents or source rows. Keep both role-specific ID lists in the query key. Drop old placeholder rows when the new index supplies a parent. **Reason and benefit** This removes unnecessary diagnostic work from a required serial request. Five alternating same-four-parent requests on the hosted app had index times of 189, 162, 156, 128 and 169 ms, versus rich-row times of 282, 211, 329, 219 and 284 ms. All requests missed the response cache. All consumed parent fields matched. This isolates the projection cost; it is not a deployed UI speedup claim. **Breaking changes** None. Membership, ordering, nesting, archive state, authorization and failure presentation retain their owners and contracts. Refs: #18323 and #18492 for the prior collection and startup work. This change addresses the remaining parent-context read. ## What Changed - Partition missing parent metadata from failed-run context. Load the two batches concurrently, with at most two batch requests in flight. - Keep richer failure rows last in the context result. Filter placeholders by company and current requested IDs. Track completed failure reads, including missing tasks, so a parent placeholder cannot reveal an unverified failure card. Keep existing verified cards mounted through refresh. - Cover delayed captions, reuse of indexed parents, refreshed parent captions, failure overlaps, resolved failures and parent-to-failure cache transitions. - Add a real browser check for delayed parent metadata and stable geometry through deferred diagnostics. Give the test its own disposable company. - Add a reusable local timing harness and update the collection verification recipe. ## Verification - Baseline source: `0710c5684243a663c09ff907011ab88838173a02`. Final measured candidate: `c8c69b5af11966b4144707a3da21e840c73c6cca`. Production UI assets were built from the same checkout and dependencies, with only the Inbox module changed between variants. - Targeted regression failed on the old implementation and passed after the change. All 58 Inbox component tests pass, including existing archive/undo and order checks. - Full workspace typecheck passes. The final UI typecheck passes. Full build passes. Token gates, map checks and diff whitespace checks pass. - All 12 collection browser checks pass, including pagination and reading-position restoration. - The full CI workflow passes on `c8c69b5af11966b4144707a3da21e840c73c6cca`, including all server, chat, workspace, serialized, runner and E2E shards. [CI run](https://github.com/paperclipai/paperclip/actions/runs/41502803275). Greptile reports 5/5 on this commit with no unresolved threads. The separate Paperclip Review check is still queued. Its first attempt saved a text result but did not complete the GitHub assessment. Normal retry was rejected because that attempt already recorded a result. The current-head review request is queued. The review service is now unavailable, so this external gate remains open. - The duplicate local `pnpm test:run` was interrupted after the equivalent CI run passed. Its six chat shards passed 1,828 tests. The general-server phase was stopped. This local full-suite run is incomplete, not a passing result. - Local synthetic fixture: four parents and 30 children, with three completed parents archived. The fixture also has 30 archived child records. No agent or provider calls ran. Mac arm64, Node 24.22.2, Chromium, production assets, 1440×900, native CPU, loopback network, fresh HTTP/query caches for each cold sample. - Five alternating local pairs produced identical 31-row membership and order and no browser errors: | Journey | Baseline median (range), ms | Candidate median (range), ms | Median paired saving, ms | | --- | --- | --- | --- | | Cold first usable Mine rows | 310 (252–435) | 258 (250–261) | 50 | | Warm Recent → Mine | 60 (56–64) | 67 (61–71) | -7 | | Task → Back to Mine | 42 (40–47) | 43 (40–45) | 0 | The final cold result has a material control limitation. The median primary-request start was 259 ms for baseline and 210 ms for candidate. Much of the cold difference occurs before the changed request. The parent response medians were 19.3 and 13.5 ms, with fewer parent IDs requested. Do not attribute the full 52 ms difference between cold medians to this fix. Four cold pairs were faster and one was 6 ms slower. Warm Recent → Mine was about 7 ms slower at the median; Back was unchanged. These runs establish no warm-navigation gain. The earlier five-pair experiment showed the same startup confound and mixed warm/Back results. All samples remain in the local evidence. A hosted final-shape comparison timed out and was cancelled by closing its owned browser tab; it supplies no result. The candidate has not been deployed. Reproduce the contract and geometry check against an isolated production UI with `pnpm exec playwright test --config tests/perf/collections/playwright.config.ts parent-context.spec.ts`. Run `tests/perf/collections/measure-mine-context.ts` against baseline and candidate loopback production origins that share one disposable API, as documented in `tests/perf/collections/README.md`. Preserve upstream startup timings as controls. Required parent responses remain inside the reveal boundary. ## Risks - Explicit-ID `index` and `rows` requests use the same company, visibility and actor filters. They do not use the inbox archive filter. An archived parent is still returned by either projection. A deleted or unreadable parent is absent in both. A second index request for a failure-parent overlap would not restore missing caption data. - A failed-run task must never reuse parent-only metadata. The query key includes each projection role. Completed reads carry explicit failure-ID coverage. The tests cover overlaps, pending role changes, late heartbeat data, known absence, and transitions to empty views. - Old parent context must not override a fresh indexed parent. The current-ID placeholder filter and caption-refresh regression cover this case. - The hosted app still has unrelated server contention. This PR reduces parent request work. It does not claim to fix all hosted loading delay. Deployment acceptance should confirm the serving revision, compare matched Mine reloads and inspect errors and row stability. Revert this change if failure items or captions regress. ## Model Used OpenAI Codex, based on GPT-6, with reasoning, tool use, browser diagnostics and code execution. The exact runtime model identifier and context-window size are not exposed by this session. ## 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> |
||
|
|
d38cdf261a |
perf(ui): speed up Tasks and Inbox startup (#18492)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Tasks and Inbox are the main entry points for that work. > - Earlier changes made their data reads and row counts smaller. > - Those changes remain, but shared controls now pull in the whole task-detail bundle. > - A cold open can also read a remembered organization before selecting the one in the URL. > - This pull request separates collection code and selects the addressed organization first. > - It warms task code after collection paint, so the next task open stays fast. ## Linked Issues or Issue Description Refs #17756, #18323, #16849, #17041, #17983, #17960, #18461. **What happened?** Tasks and Inbox still use their optimized index reads and row budgets. However, small shared controls and hooks were placed in the task-detail chunk. A collection had to download that whole chunk. The HTML also preloaded it on every route. The original production profile loaded about 6.5 MB of decoded JavaScript before useful rows, or 1.9 MB transferred with compression. Company bootstrap could select a different remembered organization before Layout selected the URL's organization. This started unnecessary company reads. A retained multi-company browser fixture reproduced two attention-count requests for different companies. **Expected behavior** Show correctly scoped, stable collection rows without waiting for task-detail code. Keep compact reads, bounded rendering, direct task preloading, immediate New Task input, and fast follow-on navigation. **Steps to reproduce** 1. Use a production UI build with Coordinator enabled and two active organizations. 2. Remember one organization, then cold-open Tasks or Mine in the other. 3. Inspect startup script and company requests before the first useful row. The baseline UI revision is `91fdf02e95`. This is a UI change. It has no API, schema, migration, or authorization changes. ## What Changed - Group the static collection dependency trees above the task-detail group. Keep the existing startup and task grouping strategy. - Preload task detail and its static dependency closure early on direct task and agent-chat URLs. Keep collection aliases out of that preload. - Fetch the immutable task chunk at low priority after a collection paints, or on a same-origin task-link hint. After a successful immutable response is fully read, module-preload the cached chunk so it can compile without executing. A failed HTTP probe skips module preload. - Prefer an addressed active organization during bootstrap. Preserve manual selection, archived-company handling, and account-scoped company lists. - Preserve a task reading anchor when a programmatic scroll event reports an unchanged offset during restore reflow. Strengthen the Back journey to wait for a completed collection navigation. - Add production-browser checks for delayed indexes, correct company scope, stable row geometry, failed speculation, and early direct-task preload. Update collection verification notes and the feature map. ## Verification Final source: `e402ab7fc6`; baseline UI: `91fdf02e95`. - All **234 focused unit cases** and **44 production-browser journeys** passed on the final source: 33 task journeys and 11 collection journeys. Coverage includes compact history, saved cards, draft persistence, avatar continuity, failed-probe recovery, delayed data, pagination, deep links, desktop/mobile and reading-position restoration through Back. Desktop and mobile screenshots were inspected. - Workspace typecheck, full production build, map checks, token gates and diff checks passed. The default local `pnpm test:run` still stops before executing tests because the existing chat-test line selector reports `No test found` (1,816 skipped). This is not a passed full local test suite. Focused tests and remote CI remain separate evidence. - Greptile reviewed the exact final commit at **5/5**, with zero open review threads. Final code CI passed. The complete check inventory is **55 successful, 3 skipped, 1 neutral**. The neutral result is the separate Paperclip Review: its agent finished without completing an assessment, so it is not a passing review score. Five alternating baseline/candidate pairs per scenario, Chromium 151.0.7922.34, 1440×900, 4× CPU, 50ms latency, approximately 9Mbps down / 1.5Mbps up. Cold cases use fresh browser contexts with normal cache writes enabled; warm cases use the same context and normal application query cache. Both previews use the server's immutable hashed-asset cache policy and uncached HTML, with real local feature settings and no request interception. All task-owned builds and suites were stopped during timing; other host activity was uncontrolled. Readiness requires useful rows and editable search, or the readable task thread and editable composer, followed by two animation frames. | Journey | Baseline median (range) | PR median (range) | Median paired saving | | --- | --- | --- | --- | | Cold Tasks | 3239 ms (3189–3333) | 2545 ms (2441–2682) | +752 ms | | Cold Inbox | 3207 ms (3203–3268) | 2679 ms (2502–3062) | +541 ms | | Warm Inbox | 717 ms (701–917) | 760 ms (745–768) | -47 ms | | Warm Tasks | 1150 ms (1126–1207) | 1136 ms (1119–1174) | +18 ms | | First task click | 943 ms (932–1008) | 1007 ms (976–1098) | -74 ms | | Back to Tasks | 584 ms (568–617) | 566 ms (559–575) | +10 ms | | Cold direct task control | 3389 ms (3377–3402) | 3415 ms (3395–3896) | -13 ms | All five pairs improved for each cold collection. The signed saving is baseline minus candidate for each pair; it is distinct from the difference of medians. Warm navigation is broadly similar. First task click was 74ms slower by median paired difference. Direct-task median paired difference was 13ms slower, with one slower 3.90s candidate sample retained in the range; this is not a claimed direct-task speedup. Completed script transfers by collection readiness fell from about **1.91MB to 1.14MB** (Tasks), and **1.90MB to 1.14MB** (Inbox). Task code warms after rows paint. At the test bandwidth, the removed 0.77MB critical transfer represents roughly 0.65s of download time; CPU and network overlap, so their savings are not added. Unthrottled loopback API control medians stayed about 17–18ms in both variants. All 30 cold samples had zero browser errors. Rejected experiments remain separate: automatic splitting produced over 200 startup requests; disabling recursive grouping slowed direct tasks; HTTP-only warming improved collection startup but slowed first task opens. The final correction preloads direct dependencies and compiles successfully cached code after paint. Routing disables HTTP caching, so intercepted runs were kept as diagnostic evidence rather than used for warm-cache acceptance; see [Playwright's cache behavior](https://playwright.dev/docs/api/class-page#page-route). Vite preview's default asset `no-cache` policy was also corrected to match the shipped server before final measurement. ## Risks - Bundle placement affects shared consumers. Browser checks cover collections and task navigation; the full PR checks also cover other routes. - Code warming still transfers the task chunk if the user stays on a populated collection. It moves that download past first paint and does not execute it. This is a startup latency improvement, not a claim that all eventual bytes disappear. - A direct click before warming finishes still loads code on demand. Direct task and chat URLs retain early module preload. - Local browser evidence does not establish a deployed staging speedup. This PR does not merge or deploy itself. ## Model Used OpenAI GPT-6 (Codex), with reasoning, tool use and local code execution. The context-window size is not exposed in this environment. ## 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 the relevant tests locally and they pass (234 unit cases and 44 browser journeys; the full-command limitation is documented above) - [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 code CI gates are green (the separate Paperclip Review is neutral because its agent did not complete an assessment) - [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> |
||
|
|
aa58fa1073 |
perf(ui): restore fast Coordinator task and inbox loading (#18323)
## Thinking Path > - Paperclip lets people manage work done by agents. > - Tasks, Inbox, and Needs You must stay usable as work history grows. > - The Coordinator views bypassed some existing collection optimizations. > - Navigation fetched complete decision cards for a count, and Tasks mounted every loaded row. > - This PR uses the canonical attention rules for small count and task-ID responses. It also restores bounded rendering and the optimized Inbox selection. > - The benefit is less data and less initial rendering work without a second definition of pending work. ## Linked Issues or Issue Description **What happened?** Coordinator navigation fetched the full attention feed on every cold collection visit. Tasks rendered the entire loaded collection. Coordinator could also select the old Inbox loader when Streamlined UI was off. **Expected behavior** Fetch only the projection needed by each surface. Start with a bounded set of rows. Keep complete task membership, accurate counts, current permissions, and stable loaded rows. **Steps to reproduce** 1. Enable Coordinator and open Tasks or Inbox with an empty browser query cache. 2. Observe a complete attention-card download for the navigation badge. 3. Open a large task list and observe that every loaded row mounts at once. 4. Disable Streamlined UI while keeping Coordinator enabled, then open Mine and observe three overlapping compact task reads. Related work: #17756, #3744, #17983, and #18312. ## What Changed - Add board-only attention count and complete task-ID projections. Reuse canonical company, privacy, addressee, deduplication, dismissal, snooze, and archive rules. Skip card bodies, plan/image reads, and presentation roster lookup. - Share the small count read across desktop and mobile navigation. Reuse the page-owned response on Needs You and Needs attention. Keep the newest known count through navigation, including zero. - Use the task-ID index for Needs attention and keep task row hydration in batches of at most 100. - Render 100 task rows initially, across the whole expanded tree. Reveal 150 more at a time through scrolling or a button. Keep existing rows through refresh and append. Defer offscreen leaf layout with shared tokens. - Keep Coordinator on the optimized Inbox when Streamlined UI is off. Use index reads for expanded project recents. - Add real-database, component, and production-build browser regression checks. Update the access and feature maps. ## Verification - All required CI checks pass on `1c68ac8957490a6c8585ba0939355f536c8120bf`: typecheck, build, server/workspace tests, serialized database suites, and eight E2E shards. Greptile is **5/5**, with its row-retention finding fixed and the review thread resolved. Storybook checks were intentionally skipped; Paperclip Review completed neutral. - Workspace typecheck and production build passed locally. The final rebased source also passed UI typecheck and production build. Token gates and map checks passed. - The attention service suite passed all 34 tests on disposable PostgreSQL. Final targeted checks cover compact projections, complete-set counts, quality approvals, snoozes, private tasks, and board/company access. Database response capture confirms compact projections do not read plans or images. All 31 OpenAPI tests passed after registering both endpoint contracts. - Six production-build browser journeys passed: desktop, mobile, Coordinator Inbox with Streamlined UI off, Needs You, Needs attention, and an older server page followed by task open/Back. They verify the initial 100-row budget, scrolling, retained DOM identity/height, one owner per attention read, complete task membership, 220 retained rows on Back, and less than 2 px of return-position difference. - The row-budget and Inbox regressions fail against original source and pass with this change. The final three affected UI suites passed 40 tests, and the broader Inbox/IssuesList suites passed 101 tests serially. ### Controlled production-build comparison Baseline `b31ec0a2dc079e32272a8f618425fe92b68bbaec` versus PR head `1c68ac8957490a6c8585ba0939355f536c8120bf`. Isolated baseline asset `index-CS9uPxMx.js`; candidate asset `index-BxJeTQ30.js`. Both UI builds used the same warm disposable API server and database, with 220 tasks and 110 pending board approvals. Chromium **151.0.7922.34**, 1440 × 900 viewport, **4× CPU throttle**, loopback with no added network latency, alternating baseline/candidate order. Cold cases use a new browser context with network cache disabled; warm cases navigate within the same context. Other host workloads are uncontrolled. Readiness requires the destination collection's first visible task row, then two animation frames. Inbox readiness waits for its canonical Mine route so previous-page rows cannot satisfy the measurement. Five paired samples per case; cold Inbox has a second five-pair confirmation wave because the first result was slower. Times below are **milliseconds**; parentheses show min–max. Paired savings are the median of individual before-minus-after pairs, not the difference between medians. | Journey | Pairs | Baseline median (range) | Candidate median (range) | Median paired saving | Faster pairs | | --- | ---: | ---: | ---: | ---: | ---: | | Cold Tasks | 5 | 2752 (2542–3025) | 2300 (2275–2524) | 328 | 5/5 | | Cold Inbox | 10 | 2536 (2283–2927) | 2582 (2117–2856) | 37 | 5/10 | | Warm Tasks navigation | 5 | 2054 (1826–2479) | 1448 (1419–1548) | 635 | 5/5 | | Warm Inbox navigation | 5 | 2020 (1485–2254) | 1568 (1289–1848) | 350 | 5/5 | | Task → Back to Tasks | 5 | 1747 (1609–1948) | 1327 (1238–1355) | 472 | 5/5 | Cold Tasks, warm Tasks, warm Inbox, and Back improved in every measured pair. **Cold Inbox latency is inconclusive:** the two waves pointed in opposite directions, with the candidate faster in 5/10 pairs. This PR claims less badge work there, not a proven cold Inbox latency improvement. The canonical badge response shrank from **200,039 to 359 decoded bytes** (encoded HTTP transfer: **8,125 to 598 bytes**). The compact response also skips card payloads, plans, images, and presentation-only roster work. These are measured mechanism reductions, separate from end-to-end latency. Needs You still owns its full card feed; Needs attention owns its complete task-ID projection. Reproduction setup and assertions are in `tests/perf/collections/README.md`. <details> <summary>Individual paired readiness measurements (ms)</summary> | Journey | Pair | Baseline | Candidate | | --- | ---: | ---: | ---: | | Cold Tasks | 1 | 3025 | 2283 | | Cold Tasks | 2 | 2542 | 2275 | | Cold Tasks | 3 | 2752 | 2424 | | Cold Tasks | 4 | 2783 | 2300 | | Cold Tasks | 5 | 2641 | 2524 | | Cold Inbox | 1 | 2927 | 2702 | | Cold Inbox | 2 | 2422 | 2629 | | Cold Inbox | 3 | 2409 | 2606 | | Cold Inbox | 4 | 2621 | 2769 | | Cold Inbox | 5 | 2539 | 2856 | | Cold Inbox | 6 | 2283 | 2117 | | Cold Inbox | 7 | 2466 | 2558 | | Cold Inbox | 8 | 2674 | 2286 | | Cold Inbox | 9 | 2696 | 2389 | | Cold Inbox | 10 | 2533 | 2183 | | Warm Tasks navigation | 1 | 2479 | 1423 | | Warm Tasks navigation | 2 | 2228 | 1548 | | Warm Tasks navigation | 3 | 2054 | 1419 | | Warm Tasks navigation | 4 | 1826 | 1448 | | Warm Tasks navigation | 5 | 1954 | 1518 | | Warm Inbox navigation | 1 | 2020 | 1661 | | Warm Inbox navigation | 2 | 2198 | 1848 | | Warm Inbox navigation | 3 | 1733 | 1497 | | Warm Inbox navigation | 4 | 2254 | 1568 | | Warm Inbox navigation | 5 | 1485 | 1289 | | Task → Back to Tasks | 1 | 1721 | 1330 | | Task → Back to Tasks | 2 | 1747 | 1275 | | Task → Back to Tasks | 3 | 1948 | 1355 | | Task → Back to Tasks | 4 | 1609 | 1327 | | Task → Back to Tasks | 5 | 1790 | 1238 | </details> ### Failed attempts and limits - The local full repository command hit embedded PostgreSQL startup failures and 16 failures in the untouched native session executor suite; it was stopped. The full local suite is not claimed green. CI on the final revision provides the broad test result. - A concurrent local UI run hit timing failures under host contention. Inbox/IssuesList subsequently passed all 101 tests serially. No tests were weakened to address these timeouts. - CI caught two integration gaps introduced during this work: missing OpenAPI entries for the new endpoints, and an attention fixture incompatible with the routine filters added on master. Both were fixed; the affected 31 OpenAPI and 40 UI tests pass. - The final revision's first CI attempt failed two untouched tests: scheduled-retry batch cancellation and the tool-access audience/archive race. Both failed jobs passed when rerun without changing the revision. Their original failed attempts remain visible in [the workflow history](https://github.com/paperclipai/paperclip/actions/runs/41083379875). - Browser evidence uses synthetic disposable data. This PR is not deployed staging or production verification. ## Risks - New attention sources must preserve canonical eligibility. Both projections call the existing collector, so they share its permissions and complete-set behavior. - The count and task-ID caches must not stand in for full decision cards. Each projection has its own key under the existing attention invalidation prefix. - A row budget can omit descendants if applied per parent. The tests cover one global budget across a large expanded tree, refresh, append, reset, and incremental loading. - Local browser evidence uses synthetic data and is not staging deployment proof. ## Model Used OpenAI Codex, GPT-6 family, with reasoning, tool use, and code execution. The exact backend model deployment ID and context window were not exposed in this session. ## 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 (affected suites; broad-run limitations are listed above) - [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> |