Skip to content

Whole-session resource timeline for the Resources drawer - #2185

Merged
simple-agent-manager[bot] merged 22 commits into
mainfrom
sam/looks-resources-details-timeline-51112h
Sep 29, 2026
Merged

simple-agent-manager[bot] merged 22 commits into
mainfrom
sam/looks-resources-details-timeline-51112h

Conversation

@simple-agent-manager

@simple-agent-manager simple-agent-manager Bot commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor

Summary

The session Resources drawer showed one 15-minute storage chunk at a time and gave no information on hover or tap. Users could not tell they were looking at a thin slice of a session (Raphaël: "I was actually feeling a bit misled"). Older history past the newest 24 chunks was unreachable, and the stat cards described only the last wake.

This replaces it with a whole-session timeline that has no chunk UI:

  • API
    • Each uploaded chunk now also stores a per-minute rollup (workspace_resource_chunks.rollup_json, additive migration 0177), computed on upload from the payload the upload path already decodes. A rollup failure never fails an upload.
    • GET /api/projects/:id/sessions/:sessionId/resource-timeline returns:
      • every chunk of the session across every wake, workspace and node, with its rollup (older chunks fall back to their summary);
      • runs per workspace, each with that workspace's reservation;
      • a disclosed cap (omittedChunkCount past WORKSPACE_RESOURCE_TIMELINE_MAX_CHUNKS, default 1000);
      • collection, which says why an empty timeline is empty: unsupported (Instant), expired (samples past retention, summary remains) or pending.
    • GET …/resource-timeline/chunks/:chunkId returns one chunk's 5-second samples, scoped to the project and session in the path (a foreign chunk returns 404).
  • Web (apps/web/src/components/chat/resource-timeline/)
    • A uPlot timeline of stacked CPU (cores), memory (used / + cache), disk and tool-call panels, with an overview strip.
    • Controls: pinch, drag and wheel zoom; range chips; Latest; Active time / Clock time; Busiest moments; a keyboard slider.
    • The readout says whether a value is a single 5-second sample or an average.
    • Reserved lines are drawn per wake, and OOM kills are marked.
    • 5-second detail is fetched only for the visible window, each chunk once (TanStack Query).
    • uPlot is in a lazy chunk only: verified with a production build that it is absent from the chat route and initial bundles.
  • Prototype removed (rule 37): the /prototype/resource-timeline route, page and mock data are deleted. The seeded stress generator is now a Playwright fixture (apps/web/tests/playwright/resource-timeline-scenarios.ts) that serves real API shapes to the real chat rail.
  • Compatible with sibling work

Idea 01M3P13H0W6EG1FS47PCG0N2EG. Task: tasks/active/2026-09-29-whole-session-resource-timeline.md.

I/O budget (rule 60)

  • Index: 1 chunk query, +1 COUNT only when capped, then +1 run/workspace query (or 2 parallel queries when empty). That is at most 3 D1 round-trips plus project auth, within the ≤8 budget.
  • Chunk read: 1 D1 query + 1 R2 read.
  • The index orders by started_at alone so idx_workspace_resource_chunks_project_session serves ORDER BY + LIMIT without sorting the session's history (EXPLAIN QUERY PLAN verified).

Validation

  • pnpm lint: api and web clean. Web has 3 warnings, all in files this PR does not touch.
  • pnpm typecheck: api and web, 0 errors.
  • pnpm test:
    • api 10,996/10,996 tests across 2,790 files, success: true (JSON reporter);
    • web 3,917/3,917 across 966 files;
    • the resource suites were re-run after the final fixes.
  • Merged main (Label resource-history tool-call spans #2183, tool-call labels) at 5b182e8: api/web typecheck 0 errors, 38/38 resource-history API tests (including Label resource-history tool-call spans #2183's callback integration test), and 22/22 resource Playwright audits.
  • Merged current main at 7c1f706 to include deployed Durable Object migration tag v21: API/web builds and typechecks pass, 18/18 focused timeline/history tests pass, and 18/18 migration-compatibility cases pass.
  • Additional validation:
    • real-SQL scope tests (attack + owner control). Deleting the project/session predicates reddens exactly the two attack tests.
    • Playwright resource audits (22 tests across 375 and 1280). The pinch test was proven to fail with pinch handling disabled.
  • N/A: no sweep/cron/alarm candidate selection changed.

Staging Verification (REQUIRED for all code changes — merge-blocking)

  • Staging deployment green: exact merged head 7c1f706 deployed successfully in runs 36573834629, 36578354066, and final uncontested restore 36582566229, including smoke tests. Earlier run 36572776653 exposed the missing v21 migration history and was resolved by merging current main. The original run 36554073091 also passed after its lockfile fix.
  • Live app verified via Playwright: token-login to app.sammy.party
  • Existing workflows confirmed working: the project chat loads and the session tool rail works.
  • New feature/fix verified on staging: see evidence below
  • N/A: no infra changes (no cloud-init, VM agent, DNS, TLS or deploy-script changes; the migration was applied by the normal pipeline)
  • Mobile and desktop verification notes added for UI changes

Staging Verification Evidence

  • Migration: 0177_workspace_resource_chunk_rollups.sql applied 2026-09-29 10:18:17, and rollup_json is present (D1 query).
  • Existing multi-wake session, uploaded before rollups (project 01KWHD8XS7MQ7R6KWXJYRHDVH4, session cbb7fed4…):
    • The drawer opened from the real rail and read "22m active over 28m · 2 wake cycles · Whole session".
    • It drew per-wake reserved lines (2 cores / 4.0 GB) and the sleep band between the wakes.
    • 15m zoom loaded 5-second detail through three real R2 chunk reads, all 200.
    • Every /resource-timeline* response was 200.
    • The only console errors on the page are 404s for GET /api/workspaces/<deleted id>. They occur without opening Resources (verified separately) and are unrelated; filed as tasks/backlog/2026-09-29-chat-page-404s-on-deleted-session-workspace.md.
  • Fresh VM session after deploy: task 01M3PBHQCGR0RMTK5GQ6YQG197 ran two CPU-busy loops on a VM workspace. Its chunk uploaded at 10:55Z through the deployed branch with rollup_json present (1,596 bytes, 181 samples).
    • The stored rollup has twelve 1-minute buckets: CPU rises to ~1.94 cores while the loops ran and falls after, memory peaks at 2.2 GB, and tool starts are counted.
    • The drawer at 1280 and 375: "15m active · Whole session", avg 1.14 / peak 1.94 cores, 8 tool calls, per-wake reservation lines (0.63 cores / 1.1 GB). Zoom fetched the chunk (200).
    • Zero failed requests and zero console errors.
    • Cleanup: the test task was completed, and its workspace 01M3PC194W66H7TDAXEMK5C1WC and node 01M3PBHXT859K212KK8CBRCSM5 were deleted; both rows are gone from D1.
  • Current-head re-verification after Label resource-history tool-call spans #2183/main merge (7c1f706): final staging run 36582566229 passed. Against retained multi-wake session cbb7fed4-33ac-469a-bc68-c9ebc5d3164f, the timeline index returned collection: collected, 2 runs, 3 chunks, and no omissions; chunk detail returned 65 five-second samples. The drawer rendered at 1280×800 and 375×667 with no document or clipped overflow and no feature-related request/console errors. The only 404s were the previously documented deleted-workspace lookups. The deployment queue stayed empty during the proof. Two aborted probe tasks were deleted, all delayed orphan nodes they spawned were removed, and D1 confirmed zero running nodes afterward.

UI Compliance Checklist (Required for UI changes)

  • Mobile-first layout verified (375×667 audits, full-screen drawer on mobile)
  • Accessibility checks completed: the timeline is a focusable slider with aria-valuetext readouts, has arrow/+/-/0/Esc keys, and has labelled controls
  • Shared UI components used or exception documented: @simple-agent-manager/ui Button/Spinner and design tokens; charts are uPlot canvases themed from tokens
  • Playwright visual audit run locally: scenarios for a 27 h / 10-wake session, a legacy agent without rollups, working set and tool labels, a truncated history (612 omitted), pending, Instant and expired. No horizontal or clipped overflow (assertNoOverflow).
  • Desktop and mobile screenshots for every changed UI surface are posted in a PR comment and linked below
  • Agent reviewed the screenshots: one issue was found and fixed. A truncated history was labelled "Whole session" and now reads "Everything shown".

UI Screenshot Evidence

All screenshots were taken with Playwright (Chromium). Local ones drive the real chat rail against the scenario fixture; staging ones are the live app at app.sammy.party.

Surface: Session Resources drawer — whole-session timeline

  • Desktop evidence: whole session desktop cursor readout desktop zoomed 15m desktop staging two-wake session zoomed staging fresh session
  • Mobile evidence: whole session mobile cursor readout mobile zoomed 15m mobile staging fresh session mobile
  • Mock/stress data used: stress-test mock data — a 27 h, 10-wake session on 3 nodes with a 9 h sleep, an OOM kill, a wake whose container never started, and one wake on a larger reservation (1,568 tool calls); live staging: a two-wake session uploaded before rollups existed, and a fresh post-deploy VM session.
  • Screenshot quality review: every screenshot was opened and reviewed at both viewports for layout, overflow, clipping and readability. Result: no overflow; sleep bands, per-wake reserved lines and the OOM marker are legible in both the dark and light themes.

Surface: Session Resources drawer — long history and older agents

  • Desktop evidence: truncated desktop legacy agent desktop
  • Mobile evidence: truncated mobile legacy agent mobile
  • Mock/stress data used: stress-test mock data — a session past the server cap (612 omitted segments); a VM agent with no rollups, no working set and unlabeled acp_tool_call spans.
  • Screenshot quality review: reviewed at both viewports. One issue was found and fixed: the truncated card said "Whole session" and now reads "Everything shown". No other issues.

Surface: Session Resources drawer — tool names in the readout

  • Desktop evidence: hostile tool name desktop long MCP name desktop
  • Mobile evidence: hostile tool name mobile long MCP name mobile
  • Mock/stress data used: stress-test mock data — fetch <img src=x onerror=alert(1)> & "quotes" 🔥; an MCP tool name over 250 characters.
  • Screenshot quality review: reviewed at both viewports. One issue was found and fixed: the long name was horizontally clipped (caught by assertNoClippedOverflow), so labels are now capped at 48 characters with an ellipsis. The hostile name renders as literal text and no <img> element is created.

Surface: Session Resources drawer — empty states

  • Desktop evidence: instant desktop pending desktop expired desktop
  • Mobile evidence: instant mobile pending mobile expired mobile
  • Mock/stress data used: stress-test mock data — an Instant (cf-container) session, a VM session with nothing uploaded yet, and a session whose samples have passed retention.
  • Screenshot quality review: reviewed at both viewports. Each state shows its own explanation and nothing that promises data that will not come. No issues.

End-to-End Verification (Required for multi-component changes)

  • Data flow traced from user input to final outcome with code path citations
  • Capability test exercises the complete happy path across system boundaries
  • All spec/doc assumptions about existing behavior verified against code
  • Manual verification steps documented below

Data Flow Trace

  1. VM agent uploads a chunk: POST /api/projects/:id/workspace-resource-history → storeWorkspaceResourceChunk (services/workspace-resource-history.ts) decodes and validates the gzip payload (validateWorkspaceResourceChunkBytes).
  2. buildStoredRollupJson → computeWorkspaceResourceRollup (services/workspace-resource-rollup.ts) → workspace_resource_chunks.rollup_json.
  3. The user opens Resources in the chat rail → SessionResourceHistoryDrawer lazy-loads ResourceTimeline → useResourceTimelineIndex → getSessionResourceTimeline (lib/api/resource-timeline.ts).
  4. GET …/resource-timeline → requireProjectAccess → getSessionResourceTimeline (services/workspace-resource-timeline.ts): chunk query, loadRunWorkspaces (reservations), and loadSessionRuntime/hasSessionSummary for empty states.
  5. indexFromApi (resource-source.ts) → rollupOverview / summaryOverview → buildSeries → uPlot panels.
  6. Zoom → useResourceTimelineData selects the visible chunks → getSessionResourceTimelineChunk → GET …/resource-timeline/chunks/:id → getSessionResourceTimelineChunk → readChunkPayload (R2, checksum-verified) → chunkDetailFromApi → 5-second series.

Capability test: apps/api/tests/unit/workspace-resource-timeline.test.ts uploads through the real storeWorkspaceResourceChunk and reads through the real index on a real SQL engine. The Playwright suite drives the real chat rail against those API shapes.

Untested Gaps

  • Reservation lines and OOM markers are canvas-drawn, so they are verified by screenshot rather than by text assertion.

Post-Mortem (Required for bug fix PRs)

N/A: not a bug fix. It is a UX redesign; the misleading one-chunk view is replaced rather than patched.

Specialist Review Evidence (Required for agent-authored PRs)

  • All local reviewers completed and findings addressed before merge
  • If any reviewer did NOT complete: needs-human-review label added and merge deferred to human (N/A: all completed)
Reviewer Status Outcome
security-auditor PASS 0 critical/high/medium. LOW: project access is now checked before chunk-id validation (935506b). LOW: the unbounded chunk span is pre-existing and confined to the uploader's own project, so it is not changed here.
cloudflare-specialist ADDRESSED MEDIUM: an id tie-break forced a sort over the session's whole history → removed and the plan verified; the index query now selects only the columns it returns (935506b). LOW: migration numbering gap and covering-index DISTINCT subquery accepted.
performance-reviewer ADDRESSED Bundle isolation and I/O budget pass. MEDIUM: pointer/wheel events set state per event → requestAnimationFrame coalescer with tests (935506b). LOW: readout memo and panels.ts at 501 lines accepted.
task-completion-validator ADDRESSED PASS on all six checks. MEDIUM: gesture paths untested → Playwright hover, drag-select, peak zoom, tap and CDP pinch added; pinch proven discriminating (b733179).

CodeRabbit Review Evidence (Required for agent-authored PRs)

  • Review requested through the trusted GitHub Actions path after the PR was otherwise ready.
  • Waited more than 15 minutes for the final-head request.
  • No CodeRabbit review or inline feedback arrived.
  • Observed outcome recorded; merge proceeds on the remaining gates under the best-effort rule from PR docs: make CodeRabbit review best-effort instead of merge-blocking #2189.

CodeRabbit Notes

The coderabbit-review label was applied. Trusted workflow runs 36567298551 and 36574196615 passed and posted human-scoped review commands; the latter targeted head 7c1f70619. CodeRabbit produced no review or inline comments after more than an hour, and its status reported Review skipped: bot user not eligible for review. The rebased head does not materially rework the feature, so the review was not requested again. Per .claude/rules/25-review-merge-gate.md, this outcome is recorded and does not block merge.

Exceptions (If any)

  • Scope: N/A
  • Rationale: N/A
  • Expiration: N/A

Agent Preflight (Required)

  • Preflight completed before code changes

Classification

  • external-api-change
  • cross-component-change
  • business-logic-change
  • public-surface-change
  • docs-sync-change
  • security-sensitive-change
  • ui-change
  • infra-change

External References

  • uPlot 1.6.32 (MIT) README and API docs (github.com/leeoniya/uPlot). Library comparison and choice are recorded in the task file: ECharts was the runner-up; Highcharts and AG Charts Enterprise were rejected on licence; Recharts has no zoom.
  • SQLite query-planner behaviour for ORDER BY + LIMIT on a composite index, verified with EXPLAIN QUERY PLAN.

Codebase Impact Analysis

  • apps/api: migration 0177, schema, services/workspace-resource-rollup.ts (new), services/workspace-resource-timeline.ts (new), upload hook in services/workspace-resource-history.ts, routes in routes/projects/workspace-resource-history.ts, env knobs.
  • apps/web: components/chat/resource-timeline/*, SessionResourceHistoryDrawer.tsx, lib/api/resource-timeline.ts (new; the unused getSessionResourceHistory client was removed), uPlot dependency.
  • The existing …/resource-history routes and the get_resource_history MCP tool are unchanged.

Documentation & Specs

  • apps/www/src/content/docs/docs/guides/session-resources.md rewritten, with new screenshots
  • apps/www/src/content/docs/docs/reference/api.md (session timeline endpoints)
  • apps/www/src/content/docs/docs/reference/configuration.md (three new vars)
  • apps/api/.env.example, .claude/skills/api-reference, .claude/skills/env-reference

Constitution & Risk Check

  • Principle XI: every new limit is configurable with a DEFAULT_*: the timeline chunk cap, rollup bucket width and max buckets. No hardcoded URLs.
  • Rule 31: the migration is additive only (ADD COLUMN); existing rows stay NULL and render from their summary.
  • Rules 11/28: project/session scoping on every query, tested on a real SQL engine with attack cases and owner controls.
  • Rule 50: per-row fault isolation for malformed rollups and reservations.
  • Rule 65: the cap keeps the newest chunks and discloses the count omitted.
  • Risk: a larger payload for very long sessions (about 1.8 KB per chunk rollup; 1000-chunk cap). The query uses the existing index without a sort.

🤖 Generated with Claude Code

@coderabbitai

coderabbitai Bot commented Sep 29, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository: raphaeltm/simple-agent-manager/.coderabbit.yaml

Review profile: CHILL

Plan: Advanced

Run ID: f858a2a8-626f-46ad-b1e3-c4e88664bfcb

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@codspeed

codspeed Bot commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 6 untouched benchmarks


Comparing sam/looks-resources-details-timeline-51112h (d5730ba) with main (7b6922b)1

Open in CodSpeed

Footnotes

  1. No successful run was found on main (219e1c0) during the generation of this report, so 7b6922b was used instead as the comparison base. There might be some changes unrelated to this pull request in this report. ↩

@simple-agent-manager simple-agent-manager Bot added the coderabbit-review Trigger CodeRabbit review for opt-in PRs label Sep 29, 2026
@raphaeltm

Copy link
Copy Markdown
Owner

@coderabbitai review

1 similar comment
@raphaeltm

Copy link
Copy Markdown
Owner

@coderabbitai review

@raphaeltm

Copy link
Copy Markdown
Owner

@coderabbitai review

raphaeltm and others added 8 commits September 29, 2026 21:05
Replace the chunk-at-a-time resource sparkline with a whole-session
timeline prototype:

- uPlot panels (CPU cores, memory used vs cache, disk, tool-call lane)
  sharing one x axis and crosshair, with reservation lines and OOM marks
- level-of-detail data layer: the index draws the whole session, 5 s
  chunks load only when zoomed past the overview and are cached forever
  (chunks are immutable), so chunks never appear in the UI
- sleeps between wake cycles compressed into labelled breaks
  (active-time axis) with a clock-time toggle
- touch scrub with a fixed readout, pinch zoom, navigator strip with
  draggable window, range presets and a busiest-moments list
- dev-only /prototype/resource-timeline route with synthetic sessions
  modelled on production ones and a proposed-vs-current backend switch

Prototype branch: not for merge as-is.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- uPlot hover only drives the cursor while a mouse is over the chart, so
  redraws and touch taps can no longer overwrite a pinned instant
- sleeps compress logarithmically (a night reads longer than a pause);
  the navigator labels sleeps of an hour or more
- finer tick steps, no clipped labels at the right edge, crowded ticks
  across a break dropped
- compact per-panel values that fit beside the legend on a phone;
  MCP tool names shown as 'tool (server)', sub-second calls in ms
- active time in view computed from runs, not sample coverage
- navigator draws loaded detail where available
- charts become one keyboard slider over time (arrows move, +/- zoom)
- mock sessions: coordinator vs builder workloads; current-backend mode
  trims runs to returned chunks like the real adapter

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Unit tests for the pure modules behind the prototype timeline: time-axis
compression, round-trips and tick placement; level-of-detail bucketing
(spike preservation, time-weighted means, gaps, disk rates, OOM counted
once); summaries and peaks; the adapter over today's API (cores from
CPU-ms, truncation detection, tool labels); view intents across axis
modes; and readout wording at each zoom level.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- the session tool-rail audit now opens Resources from the real rail
  button against today's /resource-history contract and asserts the
  whole-session readout, the OOM call-out, no chunk controls, and a
  keyboard-driven cursor reading
- mock samples carry the collector's 5 s interval, and every chunk
  the view needs returns detail
- adapter: when the server thinned a chunk, each kept sample stands
  for the time since the previous one (never across a sampler gap) and
  is no longer reported as an exact 5 s measurement

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…llups

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…SQL engine

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
raphaeltm and others added 13 commits September 29, 2026 21:06
…pe route

The drawer now reads /resource-timeline (every chunk, per-minute rollups,
per-run reservations, collection state) and fetches 5 s chunks on zoom from
/resource-timeline/chunks/:id. The prototype page and its mock data are gone;
the stress scenarios live on as a Playwright fixture that serves real API
shapes to the real chat rail.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…sion timeline

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ailure isolation

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…imeline query

- Pan, pinch, wheel and navigator drags apply at most one view change per
  animation frame; rapid wheel events build on the pending range.
- The timeline index orders by started_at alone so the session index serves
  ORDER BY + LIMIT without sorting the session's whole history, and selects
  only the columns it returns.
- The chunk route checks project access before validating the chunk id.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…real timeline

Touch runs through CDP touch events so pointer capture and pointerType
behave as on a phone. The pinch test was verified to fail with pinch
handling disabled.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The prototype's lockfile update bumped @better-auth/utils to 0.5.0, which
duplicated better-auth's core types and broke the api build (TS2742 in
auth.ts). Regenerated from main's lockfile so uplot is the only change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ment

uPlot reports its cursor on redraws too, so with a mouse left over the chart
(full-screen mobile drawer, or a desktop user reaching for the keyboard) the
next data load reset the moment chosen with the arrow keys. Hover now drives
the cursor only after the mouse moves again. Reproduced 4/6 on the 390px
project in CI and locally; 8/8 after.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@simple-agent-manager
simple-agent-manager Bot force-pushed the sam/looks-resources-details-timeline-51112h branch from 7c1f706 to af65f2f Compare September 29, 2026 21:09
@simple-agent-manager simple-agent-manager Bot removed the needs-human-review Agent could not complete all review gates — human must approve before merge label Sep 29, 2026
@sonarqubecloud

Copy link
Copy Markdown

@simple-agent-manager
simple-agent-manager Bot merged commit 2075aa0 into main Sep 29, 2026
30 checks passed
@simple-agent-manager
simple-agent-manager Bot deleted the sam/looks-resources-details-timeline-51112h branch September 29, 2026 21:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

coderabbit-review Trigger CodeRabbit review for opt-in PRs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant