Files
PaperClipAI/tests/perf/issue-detail
DottaandPaperclip 7e27bc5007 fix(tasks): keep anchored opens compact and stabilize saved cards (#18092)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Task pages must make the current instruction and recent conversation
readable quickly.
> - Compact startup avoids reading all earlier messages and run
activity.
> - Every URL fragment previously selected the full-history path, even
for documents.
> - Saved document cards also arrived after the conversation was
visible. PR statistics could add another row later.
> - This pull request keeps anchors compact and reveals the saved
conversation structure together.
> - The benefit is stable reading position without loading unrelated
history.

## Linked Issues or Issue Description

Related: #17593 introduced compact startup. #14667 covers earlier reveal
and scroll work. This fix retains the bounded history contract.

**What happened?**

Opening a task document link loaded all task history. Ordinary cold
opens could reveal messages before saved document cards and plans
arrived. Later PR metadata added a statistics row and changed card
height.

**Expected behavior**

Every URL fragment keeps compact startup. Document links open their
pane. Older-comment links fetch only the target comment. Saved cards
keep their geometry after first reveal.

**Steps to reproduce**

1. Create a task with many comments, a saved plan, documents and saved
PR work products.
2. Delay the enriched task response and open the task. Observe cards
inserted after messages appear.
3. Open a document fragment. Observe full comment, activity and run
reads.
4. Delay PR metadata refresh. Observe each card grow when diff counts
arrive.

## What Changed

- Remove fragment and tab checks from automatic history expansion.
Resolve validated comment UUIDs through the authorized single-comment
endpoint, encode their path components, retain fetched targets across
document navigation, and preserve cancellation/deletion cache updates.
- Include the saved plan, document metadata and local work-product
projection in the core task read. Skip recovery, workspace and
related-task enrichment. Do not refresh providers. Summary queries no
longer select other document bodies.
- Seed saved work-product and plan queries from core, including already
pending or errored reads, without replacing known lists or an
authoritative empty result. Coordinate the bounded recent reads, saved
cards, latest transcript and settled initial pane width before first
reveal. Keep the thread and composer mounted during refresh and explicit
expansion.
- Open continuation summaries in the document pane. Reserve PR
statistics geometry while provider metadata loads.
- Add a reusable synthetic local task, nine browser checks, frame
measurements and video. Extend the PostgreSQL core-route fixture with a
saved PR row and assert its identity, URL, state and stored metadata
survive the response. Update design guidance and capability maps.

## Verification

- Red: visible document/plan cards changed from 0 to 1 to 4; thread
height grew from 690 to 1,432 pixels. Green: all seven saved cards
appear before reveal, with constant thread height and zero per-card
movement in the final reviewed browser run. The final 1,492-pixel layout
includes the reserved PR statistics lines.
- Red: delayed PR diff counts changed all three cards from 62 to 82
pixels. Green: their heights stay at 82 pixels before and after metadata
refresh.
- Nine browser journeys pass: delayed enrichment,
document/comment/unknown/continuation anchors, document clicks and
explicit history expansion with a retained draft, missing-comment retry,
delayed PR statistics, and retained older-comment position after
document navigation.
- 583 focused UI tests passed on `c91fa107ba`. After the plan-cache
follow-up, all 212 affected page/cache/plan-hook tests and UI typecheck
pass, including 14 plan-hook cases. The original 16 focused PostgreSQL
tests passed for the server changes.
- Merge-review red: holding the duplicate stored work-products read
blocked the first reveal past 10 seconds despite core already containing
the saved cards. Both empty and populated core projections now reveal
while that request remains pending. Malformed-comment tests prove no
target request is made; API tests prove path encoding and abort-signal
forwarding.
- The populated core-route test now inserts a real saved PR work product
alongside the plan and documents, then checks the complete saved
projection through HTTP. All ten task cold-open PostgreSQL tests pass.
- Plan-cache review red: an existing pending or errored plan query
prevented the saved core plan from reaching the consumer. Four real-hook
cases failed before the data-presence fix and pass afterward, for both
present and absent plans. A separately fetched newer plan or known
absent plan remains authoritative.
- Further layout red: the initial properties pane reduced visible thread
width from 775 to 742 pixels after reveal. The reveal now waits for two
stable width frames; the browser check includes width, height, card
counts and per-card geometry.
- `pnpm -r typecheck` and `pnpm build` passed for the original change;
UI typecheck and build pass after review fixes. Token, module-boundary
and map checks pass. `pnpm test:run` was stopped after about 15 minutes
in the serialized server lane. No full local test-suite pass is claimed.
On the earlier head, hosted build/typecheck and all Vitest lanes passed;
one E2E shard failed because the agent-configuration clipboard helper
copied page text into its YAML parser. On `c91fa107ba`, Greptile was 5/5
and every E2E shard passed, including the earlier clipboard case. One
unchanged Discord chat-binding test in server shard 8 returned false
after 185 ms; its 16-test integration file passes locally without
changes. The CI cause remains unestablished. On `be436ce492`, both
server shard 8 and E2E shard 7 passed without changing those tests or
their product code. On final head `e357b3bced`, all CI jobs pass,
including full general and serialized tests, all eight E2E shards,
typecheck, build and the aggregate verification gate. Exact-head
Greptile is 5/5 with no findings. The overall status rollup contains 55
successes, two intentionally skipped Storybook checks and a neutral
Paperclip Review. That advisory review ended without a complete
assessment; all previously posted findings are resolved and it added no
current findings.
- Test startup exceeded an initial 5-second deadline once while
development assets and other checks were active. The final browser
checks allow 10 seconds. These runs establish geometry and bounded
requests; they do not establish a reliable latency improvement. An
initial 503 error fixture exercised global reconnect/backoff. The
target-comment failure test uses a terminal 404.
- Browser data is synthetic. Provider metadata is simulated for the
delayed-response check. No staging deployment or live provider execution
is claimed.

## Risks

- Core task reads now include local saved-card queries and the saved
plan body. Other document bodies and all historical run activity remain
outside that path.
- First reveal waits for the bounded current structure. The existing
15-second incomplete-history fallback and inline retry remain available.
- Continuation-summary links open in the document pane in the current
task interface. Classic tasks keep their existing surface.
- No migration or mutation permission change.

## Model Used

OpenAI Codex, GPT-6 family, with reasoning, code editing, shell tools
and browser testing. The exact serving model ID and context-window size
are 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
- [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-10-29 09:13:01 -05:00
..

Issue-detail performance baseline

Run the repeatable baseline from the repository root:

pnpm exec playwright test --config tests/perf/issue-detail/playwright.config.ts

The rig starts an isolated seeded Paperclip instance, runs five samples for each scenario/profile, and writes median-ready raw data plus a Markdown table to test-results/issue-detail-perf/.

Scenarios:

  • S1 warm in-app navigation: loads the Issues list, clears the waterfall, and clicks the seeded issue.
  • S2 cold open: creates a fresh browser context and deep-links to the seeded issue.

Profiles:

  • Unthrottled.
  • Fast 4G network with 4x CPU slowdown.

Override the sample count (minimum five) or port when needed:

PAPERCLIP_ISSUE_PERF_RUNS=7 PAPERCLIP_ISSUE_PERF_PORT=3210 pnpm exec playwright test --config tests/perf/issue-detail/playwright.config.ts

Outputs include baseline.md, baseline.json, and a Chrome trace for the first run of each scenario/profile. Open *.trace.json in Chrome DevTools Performance to inspect the issue-detail:* user-timing marks.

Set PAPERCLIP_ISSUE_PERF_PROFILE=1 to capture actual Chrome CPU samples and conversation-readiness transitions in one diagnostic sample per scenario/profile. Import the resulting *.cpuprofile in DevTools and inspect *.readiness.json for the task, comments, metadata, activity, runs, runtime, plan and transcript gates. Each gate records changes with detail.ready; use its last transition before content paint when a gate becomes pending after mount. These diagnostic runs include profiler overhead. Run without the flag for before/after latency claims. Readiness marks stay in the local browser and contain only fixed gate names and booleans; the harness enables them before navigation.

For bundle comparisons, build the UI and serve the production assets from an isolated local instance with PAPERCLIP_UI_DEV_MIDDLEWARE=false. The default managed server above uses development middleware, which does not reproduce production chunk loading. Keep the server, database, browser profile and sample count the same for both builds, and avoid concurrent builds or test suites while measuring latency.

Copy the first run's output outside test-results/issue-detail-perf, then reuse its persisted task with PAPERCLIP_ISSUE_PERF_SEED_FILE=/path/to/before/baseline.json and PAPERCLIP_ISSUE_PERF_BASE_URL pointing to that disposable instance. The harness validates the task identity before measuring. Network spans in the trace use recorded request start/end timestamps relative to task navigation; they include completed requests observed during the sample, even after content paint.

Task layout stability

compact-startup.spec.ts keeps a synthetic local reproduction with 24 messages, a plan, three documents and three saved PR cards. It holds the enriched task response, records each visible frame's card count and geometry, and rejects cards inserted after the conversation becomes readable. It also checks document, older-comment and unknown anchors without full comments/activity/run reads. Run it with the same loopback-only URL override below. The fixture URL is saved in test-results/compact-startup-fixture.json for manual inspection and reuse.

layout-stability.spec.ts exercises the real task route, including Inbox navigation, with 160 Markdown comments and a resolved interaction. It delays initial comments, tests failures and retry, tracks a reading anchor across media growth, composer resizing, properties toggles, older-page loading and Back navigation, and covers mobile reduced motion and explicit comment links. The eight scenarios also exercise same-task hash navigation without remounting on desktop and mobile, and stalled native/log reads that expose Retry after the 15-second request deadline. plan-startup.spec.ts also opens tasks with and without a saved plan while blocking the separate plan endpoint. Both must reveal the saved conversation from the task response without issuing that redundant read. It also checks task-list navigation, where a list-only snapshot needs one normal plan fetch and must still show a saved plan when present. Videos and per-frame layout.json measurements are written under each test's output directory. The two-pixel assertion measures a logical row's viewport offset; total scroll offset legitimately changes when history is prepended.

Ordinary task opens defer the concealed history and composer until their initial data is ready. The skeleton and scroll/composer containers retain their geometry. Comment-link navigation prepares content eagerly so the target can be positioned before reveal. Revealed content stays mounted during refresh. The draft scenario holds a background task read, checks the same editor remains mounted, reloads the saved draft, sends one reply, and independently checks its persisted comment.

To run against an existing disposable local test-drive instance:

PAPERCLIP_ISSUE_PERF_BASE_URL=http://127.0.0.1:3102 \
  pnpm exec playwright test --config tests/perf/issue-detail/playwright.config.ts layout-stability.spec.ts

The suite creates its own company and fixtures. The URL override accepts only loopback origins and rejects remote hosts. Use a disposable local instance, not a shared or production instance. Without the override, the harness starts its own isolated instance as before. Live provider walkthroughs additionally require a configured native Paperclip runner and Codex authentication; deterministic browser fixtures do not substitute for watching an actual provider run.

For the live walkthrough, first assign a disposable task to a native Paperclip runner configured with the Codex provider. Its scratch project should contain a small sum.mjs fixture. The script sends a paced job, scrolls up, disconnects and reconnects, steers a follow-up, and records through completion:

PAPERCLIP_LAYOUT_LIVE_URL=http://127.0.0.1:3102/LAY/issues/LAY-8 \
  node tests/perf/issue-detail/live-feed.walkthrough.mjs

Inspect test-results/task-layout/live-acceptance/ for the video, screenshots, per-frame positions, layout shifts, browser timing counters, and reading-anchor measurement. The live script rejects non-local URLs and uses real provider capacity. Review the video as well as the assertions: layout-shift scores alone do not capture programmatic scrolling or replacement flashes.