Skip to content

test(34): E2E test expansion and staging performance baselines#392

Merged
FSM1 merged 35 commits into
mainfrom
phase-34-e2e-test-expansion-staging-baselines
Mar 29, 2026
Merged

test(34): E2E test expansion and staging performance baselines#392
FSM1 merged 35 commits into
mainfrom
phase-34-e2e-test-expansion-staging-baselines

Conversation

@FSM1

@FSM1 FSM1 commented Mar 29, 2026

Copy link
Copy Markdown
Owner

Summary

  • Account cleanup: Shared deleteAccountViaPage helper wired into all 10 E2E specs to prevent orphaned test accounts in the database
  • Media/streaming E2E: New streaming-playback.spec.ts (6 tests) and media-preview.spec.ts (5 tests) covering AES-CTR streaming, GCM fallback, PDF/video/audio preview dialogs
  • Batch download E2E: New batch-download.spec.ts (5 tests) covering multi-select, selection bar, and download event verification
  • Staging baselines: Journey timing (login 22.9s, upload 906ms, share 1.5s), SDK sustained load (200 clients, 11,174 ops, 0.17% error rate), BYO capacity ceiling (50-1000 clients via Pinata)
  • Infra fixes: Playwright config supports BASE_URL env var for staging runs, cleanup helper derives API URL from page origin
  • Removed: Browser-based load test (load-test.spec.ts) — redundant with SDK load harness that drives 200+ headless clients
  • CI: BYO scenarios added to load test workflow with per-run configurable provider inputs

Staging Baseline Results

Test Key Metrics
Journey timing Login: 22.9s, Upload: 906ms, Share: 1.5s
SDK sustained (200 clients) 11,174 ops, 0.17% error rate, upload p50=8.1s
BYO ceiling (Pinata) Pin p50=718ms works; register-cid returns 400 (tracked in todo)

Test plan

  • cd tests/web-e2e && pnpm exec playwright test --list shows 16 new tests across 3 specs
  • grep -r deleteAccountViaPage tests/web-e2e/tests/ | wc -l shows cleanup in 10 specs
  • Media fixtures exist: ls tests/web-e2e/fixtures/files/test-video.mp4
  • Staging baselines captured: ls tests/web-e2e/baselines/ tests/load/baselines/
  • Browser load test removed: load-test.spec.ts and playwright.load.config.ts no longer exist

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Tests

    • Added E2E coverage: AES‑CTR streaming playback, media preview dialogs, batch downloads, and new serial suites.
    • Improved teardown: best‑effort account deletion added to E2E teardowns; media/fixture helpers introduced.
    • Playwright config updated to support external staging targets; legacy dedicated load-test config removed.
  • Chores

    • Captured staging baselines (journey timing, sustained load, BYO capacity) and added a BYO‑IPFS load test plan and CI inputs.
  • Documentation

    • Added investigation notes, verification reports, and operational rules for staging load testing.

FSM1 and others added 27 commits March 29, 2026 03:33
Entire-Checkpoint: 5e6526bb9f68
- Create tests/load/baselines/byo-load-test-plan.md with execution plan
- Document 3 BYO load test scenarios (upload, mixed, capacity ceiling)
- Include environment variables, execution commands, and expected metrics
- Reference Phase 19.2/22 non-BYO baselines from docs/CAPACITY.md
- Pinata recommended as provider (PinataProvider already implemented)
- Explicit DEFERRED status: awaiting external IPFS provider infrastructure
- Create 34-04-SUMMARY.md (partial: Task 1 complete, Task 2 pending)
- Update STATE.md position to Phase 34 Plan 04 checkpoint
- Update ROADMAP.md plan progress for Phase 34
…into multi-account utility

- Add cleanup-helpers.ts with deleteAccountViaPage that calls /auth/refresh + DELETE /auth/account
- Wraps entire function in try/catch with console.warn (never throws in afterAll teardown)
- Update closeWalletTestAccounts to delete accounts before closing browser contexts
- Each account deletion wrapped individually so one failure doesn't block others
- Single-account specs (full-workflow, search, recycle-bin, mfa, conflict, wallet-login): import + call deleteAccountViaPage before context.close()
- Multi-account specs (sharing, writable-shares, invite-link): closeWalletTestAccounts now handles deletion (from Task 1)
- Hybrid spec (journey-timing): deleteAccountViaPage for Alice + closeWalletTestAccounts for Bob
- wallet-login.spec.ts uses afterEach (fixture-based tests) for TC09 cleanup
- conflict-detection: single deletion suffices (both sessions share same wallet identity)
- Create 34-01-SUMMARY.md with execution results
- Update STATE.md position to Phase 34 Plan 1/4
- Update ROADMAP.md with plan progress
- Add test-video.mp4 (300KB, >256KB CTR threshold)
- Add test-video-small.mp4 (100KB, <256KB GCM fallback)
- Add test-audio.mp3 (300KB, >256KB CTR threshold)
- Add test-document.pdf (valid PDF with text content)
- Add createTestMediaFile() to test-files.ts for fixture copying
- Update .gitignore to track committed media fixtures
- streaming-playback.spec.ts: 6 tests covering CTR mode activation,
  encrypted badge, decrypt progress, and GCM blob URL fallback
- media-preview.spec.ts: 5 tests covering PDF canvas viewer,
  video player modal, audio player modal, and corrupt file error state
- Both suites use deleteAccountViaPage cleanup in afterAll
- SUMMARY.md documents 11 new E2E tests across 2 spec files
- STATE.md updated to plan 2/4 complete
- ROADMAP.md progress updated for phase 34
- playwright.config.ts: support BASE_URL env var, skip webServer for external targets
- journey-timing.spec.ts: increase wallet init timeout to 45s for staging
- cleanup-helpers.ts: derive API URL from page URL for staging environments
- baselines/staging-journey-timing.json: captured staging journey timing baselines

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 0eb210591a47
- 5 tests covering multi-file selection and batch download via selection action bar
- Verifies selection bar count, download event trigger, and batch context menu
- Uses deleteAccountViaPage for afterAll cleanup
- Confirms batch download fires individual file downloads (not zip)
- SUMMARY.md with task commits and plan metrics
- STATE.md updated with plan progress
- ROADMAP.md updated via gsd-tools

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
5 clients x ~70 ops: 305/395 succeeded (0.71 ops/sec).
C4/C5 context exhaustion visible at 5 concurrent browser sessions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: b0a8b6b36d59
Pinata provider now configured in tests/load/.env. Updated execution
instructions and prerequisites.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 2113055f92e4
200 clients requested, 10 created due to 429 rate limit. Documents throttle
bypass gap in SDK test harness for future fix.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: c3955e674528
Journey timing, browser load test, and SDK sustained load baselines
all captured. BYO plan upgraded to ACTIVE with Pinata.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: b95dfd042bfe
Documents investigation into why THROTTLE_BYPASS_SECRET doesn't prevent
429s in vitest load tests against staging, despite working with curl
and direct Node fetch. CI avoids the issue via NODE_ENV=test.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: a97d8f0b009f
… bug

Root cause was running two load tests simultaneously against staging.
Bypass header works correctly when tests run sequentially.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: c6e17a344aa0
200 clients x 2 ops/sec x 5min = 11,174 ops, 0.17% error rate.
createFolder p50=6.5s, uploadFile p50=8.1s, deleteItem p50=3.2s.
p95 latency elevated under full contention but error rate minimal.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 1cb9ba053541
…ures

All 5 tiers completed: 50, 100, 200, 500, 1000 clients. Account creation
and API ops succeeded but all Pinata byo-pin operations failed with fetch
errors. Pinata endpoint or auth config needs investigation.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 18e9b7f4db69
403 error confirms JWT auth works but quota is exhausted. Need paid
plan or fresh account for successful pin baselines.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 5d89428fe42f
200-client sustained load: 11,174 ops, 0.17% error rate.
BYO ceiling: all 5 tiers ran, Pinata free tier limits exhausted.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 5eff2a8b6367
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 2df3efa96a64
- Merge double page.evaluate into single call in cleanup-helpers.ts
- Replace inline deleteAccount in load-test.spec.ts with shared helper
- Move dynamic fs/path imports to top-level in media-preview.spec.ts
- Fix TOCTOU: try/catch unlinkSync instead of existsSync check
- Use try/finally for corrupt file cleanup to prevent leaks

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 702da977d914
The SDK load test harness (tests/load/) drives 200+ headless clients
directly against the API with per-operation metrics. The Playwright
browser load test (5 Chromium tabs) measured browser overhead more
than API performance and provided no additional signal.

Removed:
- tests/web-e2e/tests/load-test.spec.ts
- tests/web-e2e/playwright.load.config.ts
- tests/web-e2e/baselines/staging-load-test.json
- testIgnore for load-test.spec.ts in playwright.config.ts

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 665ca031ee1a
@coderabbitai

coderabbitai Bot commented Mar 29, 2026

Copy link
Copy Markdown

Warning

Rate limit exceeded

@FSM1 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 10 minutes and 52 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 10 minutes and 52 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: bde016a8-784f-46d1-a385-14d9a94c062c

📥 Commits

Reviewing files that changed from the base of the PR and between 07bf3ea and 9ca1fbb.

📒 Files selected for processing (2)
  • tests/web-e2e/baselines/staging-journey-timing.json
  • tests/web-e2e/utils/cleanup-helpers.ts

Walkthrough

Phase 34 marked complete; adds an in-page Playwright account-teardown helper wired into many E2E specs, three new serial E2E suites and media fixture utilities, removes the previous Playwright load-test spec/config, and adds BYO‑IPFS load-test plans, workflow inputs, and staging baseline artifacts.

Changes

Cohort / File(s) Summary
Planning & Roadmap
.planning/ROADMAP.md, .planning/STATE.md, .planning/todos/..., .planning/phases/34-*
Mark Phase 34 complete; add plans, summaries, research, verification, and todos for E2E expansion and BYO‑IPFS; update counters, timestamps, and performance table rows.
E2E Teardown Helper & Multi-account
tests/web-e2e/utils/cleanup-helpers.ts, tests/web-e2e/utils/multi-account-wallet.ts
Add exported deleteAccountViaPage(page) (best-effort in-page auth refresh + DELETE) and update closeWalletTestAccounts to call it per-account before closing contexts with per-account try/catch.
Spec Teardown Wiring
tests/web-e2e/tests/... (full-workflow.spec.ts, search-workflow.spec.ts, recycle-bin.spec.ts, mfa-flows.spec.ts, journey-timing.spec.ts, conflict-detection.spec.ts, wallet-login.spec.ts, ...)
Import and invoke deleteAccountViaPage in afterAll/afterEach across many suites; journey-timing increases wallet init timeout to 45s.
New Serial E2E Suites
tests/web-e2e/tests/streaming-playback.spec.ts, tests/web-e2e/tests/media-preview.spec.ts, tests/web-e2e/tests/batch-download.spec.ts
Add three serial Playwright suites covering AES-CTR streaming playback, media preview (PDF/video/audio plus corrupt-file error), and batch-download selection/download behaviors.
Media Fixtures & Test-file Utilities
tests/web-e2e/utils/test-files.ts, tests/web-e2e/.gitignore, tests/web-e2e/fixtures/files/*
Add createTestMediaFile(sourceFixture, name?), prevent overwriting committed fixtures, track created files for cleanup; un-ignore four committed media fixtures so they are tracked.
Playwright Configs
tests/web-e2e/playwright.config.ts, (deleted) tests/web-e2e/playwright.load.config.ts
Remove dedicated load config; main config adds isExternalTarget based on BASE_URL, uses BASE_URL for use.baseURL, and omits local webServer when targeting external hosts.
Removed Load-test Spec
tests/web-e2e/tests/load-test.spec.ts
Delete prior concurrent Playwright load-test spec (workload moved to dedicated load harness/plans).
Load Testing Plans & Baselines
tests/load/baselines/byo-load-test-plan.md, tests/load/baselines/staging-byo-capacity-ceiling.json, tests/load/baselines/staging-sustained-load.json
Add BYO‑IPFS load test plan and staging baseline JSONs capturing capacity-ceiling pin errors and sustained-load metrics (ops, latencies, threshold violations).
E2E Baseline
tests/web-e2e/baselines/staging-journey-timing.json
Add staging journey timing baseline with per-journey and phase durations.
CI Load-test Workflow
.github/workflows/load-test.yml
Add BYO‑IPFS scenario choices and BYO-related workflow_dispatch inputs; conditionally export BYO env vars and fail when BYO auth token is missing for byo scenarios.

Sequence Diagram(s)

mermaid
sequenceDiagram
participant Client as Load Test Client(s)
participant StagingAPI as Staging API (auth / account)
participant Throttler as Throttler
participant BYO as BYO Provider (Pinata)
Note over Client,StagingAPI: Concurrent SDK sustained-load + BYO scenarios against staging
Client->>StagingAPI: POST /create-account (many concurrent)
StagingAPI->>Throttler: check rate & bypass header
Throttler-->>StagingAPI: allow / track (may honor bypass)
Client->>BYO: POST /pin (byo-pin) with BYO auth
BYO-->>Client: 200 or 403 (quota)
StagingAPI->>BYO: POST /register-cid or /ipns-publish (server-side)
BYO-->>StagingAPI: 200 or 400 (register-cid failures)
Note over StagingAPI,Throttler: Combined sustained load can saturate server → 429 ThrottlerException observed after ~10 account creations

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'test(34): E2E test expansion and staging performance baselines' clearly and concisely summarizes the main changes: Phase 34 testing work covering new E2E test specs and staging performance baseline capture.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch phase-34-e2e-test-expansion-staging-baselines

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 and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@tests/load/baselines/byo-load-test-plan.md`:
- Around line 3-13: The document incorrectly marks the BYO load test as ACTIVE
and claims BYO config seeding is completed; update
tests/load/baselines/byo-load-test-plan.md to set the status to DEFERRED and
change the prerequisites text to reflect that BYO provider config seeding is not
persisted by the harness (remove or reword the claim that "Test harness creates
accounts with BYO provider config automatically"), referencing the
client-pool.ts behavior and the open TODO around register-cid 400s to clarify
that seeding is not done automatically and that manual setup or future
persistence is required.

In `@tests/web-e2e/tests/batch-download.spec.ts`:
- Around line 142-153: The test title says it should verify the batch context
menu shows a download option, but it only asserts the menu and header text; add
an assertion that the download item is present (e.g. after obtaining headerText
and isBatchMenu, call a contextMenu method to check for the download entry).
Locate the block using fileList.rightClickItem(file2Name),
contextMenu.waitForOpen(), isBatchMenu() and getHeaderText(), and add a line
such as expect(await contextMenu.hasMenuItem('Download')).toBe(true) or
expect((await contextMenu.getMenuItems()).map(t =>
t.toLowerCase())).toContain('download') immediately after the header assertion
so the test actually verifies the download option is shown.

In `@tests/web-e2e/tests/media-preview.spec.ts`:
- Around line 3-6: The test builds a fixture path using process.cwd() (fragile)
instead of the deterministic helper; replace any usage of process.cwd() in the
media-preview.spec.ts test where the fixture path is constructed with
getTestFilePath() from the test-file utilities, update the import list to
include getTestFilePath alongside createTestMediaFile and cleanupTestFiles, and
pass the resulting path into createTestMediaFile (or wherever the path is
consumed) so the fixture resolution is consistent across Playwright run
contexts.

In `@tests/web-e2e/utils/test-files.ts`:
- Around line 146-156: The createTestMediaFile function currently accepts raw
sourceFixture and name allowing ../ to escape FIXTURES_DIR; fix it by
normalizing and validating both fixturePath and filePath after resolving them
(use resolve and then ensure path.relative(FIXTURES_DIR, resolvedPath) does not
start with '..' and is not absolute outside the directory), reject or throw if
either resolves outside FIXTURES_DIR, and only then perform copyFileSync and
push the validated filePath into createdFiles; reference the createTestMediaFile
function and the variables fixturePath, filePath, and createdFiles when making
this change.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: e673b5a6-923d-4917-a32a-016ae9274c07

📥 Commits

Reviewing files that changed from the base of the PR and between a9604a1 and 5801284.

⛔ Files ignored due to path filters (4)
  • tests/web-e2e/fixtures/files/test-audio.mp3 is excluded by !**/*.mp3
  • tests/web-e2e/fixtures/files/test-document.pdf is excluded by !**/*.pdf
  • tests/web-e2e/fixtures/files/test-video-small.mp4 is excluded by !**/*.mp4
  • tests/web-e2e/fixtures/files/test-video.mp4 is excluded by !**/*.mp4
📒 Files selected for processing (35)
  • .learnings/2026-03-29-staging-load-test-throttle-bypass.md
  • .planning/ROADMAP.md
  • .planning/STATE.md
  • .planning/phases/34-e2e-test-expansion-staging-baselines/34-01-PLAN.md
  • .planning/phases/34-e2e-test-expansion-staging-baselines/34-01-SUMMARY.md
  • .planning/phases/34-e2e-test-expansion-staging-baselines/34-02-PLAN.md
  • .planning/phases/34-e2e-test-expansion-staging-baselines/34-02-SUMMARY.md
  • .planning/phases/34-e2e-test-expansion-staging-baselines/34-03-PLAN.md
  • .planning/phases/34-e2e-test-expansion-staging-baselines/34-03-SUMMARY.md
  • .planning/phases/34-e2e-test-expansion-staging-baselines/34-04-PLAN.md
  • .planning/phases/34-e2e-test-expansion-staging-baselines/34-04-SUMMARY.md
  • .planning/phases/34-e2e-test-expansion-staging-baselines/34-RESEARCH.md
  • .planning/phases/34-e2e-test-expansion-staging-baselines/34-VERIFICATION.md
  • .planning/todos/pending/2026-03-29-debug-byo-ipfs-register-cid-400-errors-on-staging.md
  • tests/load/baselines/byo-load-test-plan.md
  • tests/load/baselines/staging-byo-capacity-ceiling.json
  • tests/load/baselines/staging-sustained-load.json
  • tests/web-e2e/.gitignore
  • tests/web-e2e/baselines/staging-journey-timing.json
  • tests/web-e2e/playwright.config.ts
  • tests/web-e2e/playwright.load.config.ts
  • tests/web-e2e/tests/batch-download.spec.ts
  • tests/web-e2e/tests/conflict-detection.spec.ts
  • tests/web-e2e/tests/full-workflow.spec.ts
  • tests/web-e2e/tests/journey-timing.spec.ts
  • tests/web-e2e/tests/load-test.spec.ts
  • tests/web-e2e/tests/media-preview.spec.ts
  • tests/web-e2e/tests/mfa-flows.spec.ts
  • tests/web-e2e/tests/recycle-bin.spec.ts
  • tests/web-e2e/tests/search-workflow.spec.ts
  • tests/web-e2e/tests/streaming-playback.spec.ts
  • tests/web-e2e/tests/wallet-login.spec.ts
  • tests/web-e2e/utils/cleanup-helpers.ts
  • tests/web-e2e/utils/multi-account-wallet.ts
  • tests/web-e2e/utils/test-files.ts
💤 Files with no reviewable changes (2)
  • tests/web-e2e/playwright.load.config.ts
  • tests/web-e2e/tests/load-test.spec.ts

Comment thread tests/load/baselines/byo-load-test-plan.md Outdated
Comment thread tests/web-e2e/tests/batch-download.spec.ts
Comment thread tests/web-e2e/tests/media-preview.spec.ts Outdated
Comment thread tests/web-e2e/utils/test-files.ts
Add byo-upload-throughput, byo-mixed-workload, byo-capacity-ceiling
to scenario dropdown. Pass BYO_IPFS_* env vars from GitHub environment
vars/secrets when targeting staging.

Requires GitHub environment config:
- vars: BYO_IPFS_ENDPOINT, BYO_IPFS_PROTOCOL, BYO_IPFS_PROVIDER_NAME
- secrets: BYO_IPFS_AUTH_TOKEN

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: a18fd3b58711

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/load-test.yml:
- Around line 180-184: Only export the BYO IPFS env vars when the workflow is
running a BYO scenario: wrap the four echo lines that set BYO_IPFS_ENDPOINT,
BYO_IPFS_AUTH_TOKEN, BYO_IPFS_PROTOCOL, and BYO_IPFS_PROVIDER_NAME in a
conditional that checks the selected scenario (e.g., check the SCENARIO/workflow
input/env value starts with "byo-" or a dedicated BYO flag) so these secrets are
not written to GITHUB_ENV for non-BYO runs; update the step containing those
echo commands to perform that conditional check before exporting.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 39031a8e-c8f8-48fa-8474-20e62e22fa47

📥 Commits

Reviewing files that changed from the base of the PR and between 5801284 and 9a76c64.

📒 Files selected for processing (1)
  • .github/workflows/load-test.yml

Comment thread .github/workflows/load-test.yml Outdated
BYO endpoint, protocol, and provider name are now workflow_dispatch
inputs with defaults — different providers can be evaluated against
each other without changing environment config.

Auth token remains a secret: LOAD_TEST_BYO_AUTH_TOKEN

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 1e025a001989
- BYO load test plan: status ACTIVE -> PARTIAL, note pending config seeding
- batch-download.spec.ts: add download menuitem assertion
- media-preview.spec.ts: use getTestFilePath instead of process.cwd
- test-files.ts: sanitize paths with basename to prevent directory traversal
- load-test.yml: scope BYO env vars to byo-* scenarios only

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: d2aece93b5bb

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Expands the Playwright E2E test suite to cover media streaming/preview and batch download flows, adds shared best-effort account cleanup to prevent orphaned test users, and records staging/load baseline artifacts and related planning docs.

Changes:

  • Added shared deleteAccountViaPage teardown helper and integrated it across E2E specs (including multi-account cleanup).
  • Added new E2E specs for AES-CTR streaming playback, media preview dialogs, and batch download; committed media fixtures.
  • Updated Playwright config to support BASE_URL overrides (and skip local webServer for external targets); removed legacy browser-based load-test config/spec; added/updated baseline + planning docs and workflow inputs for BYO load testing.

Reviewed changes

Copilot reviewed 36 out of 40 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
tests/web-e2e/utils/test-files.ts Adds createTestMediaFile helper to copy committed media fixtures and track cleanup.
tests/web-e2e/utils/multi-account-wallet.ts Ensures multi-account teardown deletes accounts before closing contexts.
tests/web-e2e/utils/cleanup-helpers.ts New helper to delete the logged-in test account via in-page fetch calls.
tests/web-e2e/tests/wallet-login.spec.ts Adds best-effort per-test account cleanup.
tests/web-e2e/tests/streaming-playback.spec.ts New E2E coverage for AES-CTR streaming vs GCM fallback behavior.
tests/web-e2e/tests/media-preview.spec.ts New E2E coverage for PDF/video/audio previews + corrupt media error path.
tests/web-e2e/tests/batch-download.spec.ts New E2E coverage for multi-select and batch download event triggering.
tests/web-e2e/tests/search-workflow.spec.ts Adds account deletion to suite teardown.
tests/web-e2e/tests/recycle-bin.spec.ts Adds account deletion to suite teardown.
tests/web-e2e/tests/mfa-flows.spec.ts Adds account deletion to suite teardown.
tests/web-e2e/tests/journey-timing.spec.ts Adds account deletion for teardown + increases wallet init timeout for staging.
tests/web-e2e/tests/full-workflow.spec.ts Adds account deletion to suite teardown.
tests/web-e2e/tests/conflict-detection.spec.ts Adds account deletion to suite teardown.
tests/web-e2e/tests/load-test.spec.ts Removes legacy browser-driven Playwright load test.
tests/web-e2e/playwright.load.config.ts Removes legacy load-test-specific Playwright config.
tests/web-e2e/playwright.config.ts Supports BASE_URL override and conditionally skips local webServer startup.
tests/web-e2e/.gitignore Allows committed media fixtures while still ignoring generated fixture files.
tests/web-e2e/fixtures/files/test-video.mp4 Adds committed video fixture for CTR streaming threshold testing.
tests/web-e2e/fixtures/files/test-video-small.mp4 Adds committed small video fixture for GCM fallback testing.
tests/web-e2e/fixtures/files/test-audio.mp3 Adds committed audio fixture for preview tests.
tests/web-e2e/fixtures/files/test-document.pdf Adds committed PDF fixture for preview tests.
tests/web-e2e/baselines/staging-journey-timing.json Adds staging journey timing baseline artifact.
tests/load/baselines/staging-sustained-load.json Adds staging sustained SDK load baseline artifact.
tests/load/baselines/staging-byo-capacity-ceiling.json Adds BYO capacity ceiling baseline artifact.
tests/load/baselines/byo-load-test-plan.md Adds BYO load-test plan doc for running/recording baselines.
.planning/todos/pending/2026-03-29-debug-byo-ipfs-register-cid-400-errors-on-staging.md Tracks follow-up investigation for staging BYO register-cid 400s.
.planning/phases/34-e2e-test-expansion-staging-baselines/34-VERIFICATION.md Adds verification report for Phase 34 deliverables.
.planning/phases/34-e2e-test-expansion-staging-baselines/34-RESEARCH.md Adds research notes supporting the E2E/baseline work.
.planning/phases/34-e2e-test-expansion-staging-baselines/34-04-SUMMARY.md Adds summary for staging baselines + BYO plan updates.
.planning/phases/34-e2e-test-expansion-staging-baselines/34-04-PLAN.md Adds plan for staging baselines + BYO plan documentation.
.planning/phases/34-e2e-test-expansion-staging-baselines/34-03-SUMMARY.md Adds summary for batch download E2E coverage.
.planning/phases/34-e2e-test-expansion-staging-baselines/34-03-PLAN.md Adds plan for batch download E2E coverage.
.planning/phases/34-e2e-test-expansion-staging-baselines/34-02-SUMMARY.md Adds summary for streaming + media preview E2E coverage and fixtures.
.planning/phases/34-e2e-test-expansion-staging-baselines/34-02-PLAN.md Adds plan for streaming + media preview E2E coverage and fixtures.
.planning/phases/34-e2e-test-expansion-staging-baselines/34-01-SUMMARY.md Adds summary for shared account cleanup wiring.
.planning/phases/34-e2e-test-expansion-staging-baselines/34-01-PLAN.md Adds plan for shared account cleanup wiring.
.planning/STATE.md Updates milestone/state tracking for Phase 34 completion.
.planning/ROADMAP.md Marks Phase 34 complete and updates success criteria wording.
.learnings/2026-03-29-staging-load-test-throttle-bypass.md Adds operational learning about staging load-test concurrency causing 429s.
.github/workflows/load-test.yml Adds BYO scenario inputs and wires BYO provider env vars for workflow runs.

Comment thread tests/web-e2e/tests/streaming-playback.spec.ts
Comment thread tests/web-e2e/tests/media-preview.spec.ts
Comment thread tests/web-e2e/tests/batch-download.spec.ts Outdated
Comment thread tests/web-e2e/utils/multi-account-wallet.ts Outdated
Comment thread .planning/STATE.md
Comment thread .planning/phases/34-e2e-test-expansion-staging-baselines/34-VERIFICATION.md Outdated
Comment thread .planning/phases/34-e2e-test-expansion-staging-baselines/34-VERIFICATION.md Outdated
Comment thread tests/web-e2e/playwright.config.ts Outdated
- Guard page/context in afterAll hooks across 3 new specs
- Wrap context.close() in try/catch in closeWalletTestAccounts
- Include 127.0.0.1 in local target detection for playwright config
- Fix VERIFICATION.md: remove stale staging-load-test.json ref, update
  sustained-load description to reflect 200-client run

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 20c3db6e1564
@codecov

codecov Bot commented Mar 29, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 61.18%. Comparing base (8cddb05) to head (9ca1fbb).
⚠️ Report is 4 commits behind head on main.

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main     #392      +/-   ##
==========================================
+ Coverage   61.15%   61.18%   +0.03%     
==========================================
  Files         132      132              
  Lines        9750     9750              
  Branches      976      978       +2     
==========================================
+ Hits         5963     5966       +3     
+ Misses       3573     3570       -3     
  Partials      214      214              
Flag Coverage Δ
api 84.36% <ø> (+0.05%) ⬆️
api-client 84.36% <ø> (+0.05%) ⬆️
core 84.36% <ø> (+0.05%) ⬆️
crypto 84.36% <ø> (+0.05%) ⬆️
sdk 84.36% <ø> (+0.05%) ⬆️
sdk-core 84.36% <ø> (+0.05%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.
see 1 file with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@FSM1

FSM1 commented Mar 29, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai please review

@coderabbitai

coderabbitai Bot commented Mar 29, 2026

Copy link
Copy Markdown

@FSM1 Sure! I'll start reviewing PR #392 right away.


🧠 Learnings used
Learnt from: FSM1
Repo: FSM1/cipher-box PR: 318
File: tests/load/src/scenarios/upload-throughput.test.ts:8-15
Timestamp: 2026-03-22T18:39:53.860Z
Learning: In `tests/load/src/scenarios/*.test.ts` (load test scenarios in FSM1/cipher-box): Load tests are measurement tools, not pass/fail correctness tests. `Promise.allSettled` is used intentionally — partial client completion is expected, and error counts are captured and reported in the metrics JSON via `aggregateAndReport`. Do NOT flag the absence of `expect(failures).toHaveLength(0)` assertions or suggest switching to `Promise.all`. The test should remain green even when some client workloads reject.

Learnt from: FSM1
Repo: FSM1/cipher-box PR: 253
File: tests/e2e-desktop/scripts/test-conflict-detection.ps1:156-157
Timestamp: 2026-03-03T14:55:05.884Z
Learning: In `tests/e2e-desktop/scripts/*.{sh,ps1}` (FUSE E2E tests): Fixed sleep-based waits after file mutations are an inherent limitation of FUSE-mount testing. The FUSE daemon provides no IPC signal or status endpoint to indicate when a debounced IPNS metadata publish completes. Tests use conservative fixed waits (e.g., 8s for initial publish accounting for 1.5s debounce + 10s safety valve, 15s for conflict resolution) and can be increased if CI proves flaky. Eliminating sleep-based waits would require exposing an IPC readiness signal from the FUSE daemon.

Learnt from: FSM1
Repo: FSM1/cipher-box PR: 318
File: tests/load/src/harness/client-pool.ts:77-80
Timestamp: 2026-03-22T18:39:41.142Z
Learning: In `tests/load/src/harness/client-pool.ts`, the shared `cipherbox/api-client` singleton `setApiClientConfig` is configured once using `clients[0].accessToken` as the `getAccessToken` callback, meaning all SDK-core calls (e.g., `ipnsControllerPublishRecord` via `updateFolderMetadataAndPublish`) authenticate as client 0 regardless of which pool client is making the call. This is a known, pre-existing design gap inherited from the initial web-app extraction of the api-client singleton. It is tracked for resolution in `.planning/todos/pending/2026-03-22-refactor-api-client-from-singleton-to-instance-scoped-axios.md` (refactor orval-generated functions to accept a per-instance axios instance). Do NOT re-flag this as a new issue in future PRs.

Learnt from: FSM1
Repo: FSM1/cipher-box PR: 318
File: tests/load/src/scenarios/sustained-load.test.ts:36-42
Timestamp: 2026-03-22T18:39:56.642Z
Learning: In `tests/load/src/scenarios/*.test.ts` (load test scenarios for `cipherbox/load-tests`): All load test scenarios intentionally use `Promise.allSettled` instead of `Promise.all` and are designed to always stay green (pass) regardless of individual client failures. These tests are performance measurement tools, not correctness tests — partial client completion is expected under high load, and error rates are captured in the metrics output. Throwing on rejected client loops would prevent collection of partial results and is explicitly rejected as a design pattern for this package.

Learnt from: FSM1
Repo: FSM1/cipher-box PR: 268
File: tests/e2e/tests/recycle-bin.spec.ts:431-446
Timestamp: 2026-03-05T01:50:38.331Z
Learning: In `tests/e2e/tests/recycle-bin.spec.ts` TC08 (`permanent delete of versioned file reclaims all quota`): The secondary quota assertion (`quotaAfter < quotaBefore`) is intentionally a best-effort, loose check. Tightening it to an exact byte delta is explicitly rejected because encryption overhead, IPFS chunking, and pinning-service metadata size variability make deterministic freed-byte calculations unreliable in E2E tests. The primary assertion is that permanent delete completes without crash (the item disappears from the bin); the quota check is only a supplementary signal when the Zustand store is accessible.
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@tests/web-e2e/tests/batch-download.spec.ts`:
- Around line 122-124: Selection is being cleared via await
page.keyboard.press('Escape') but tests don't wait for the UI to reflect that,
causing flaky inherited selection; after each await
page.keyboard.press('Escape') (the two occurrences in this spec), add an
explicit await page.waitForSelector('<selection-indicator-selector>', { state:
'hidden' }) — where <selection-indicator-selector> is the DOM element used by
the app to show selected items (e.g. a selected row class, selection toolbar, or
overlay) so the test only proceeds once the selection UI is gone.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 2b30ae50-e16f-4c1e-9f0d-ef36a90a204b

📥 Commits

Reviewing files that changed from the base of the PR and between b87233d and 302da5c.

📒 Files selected for processing (9)
  • .github/workflows/load-test.yml
  • .planning/phases/34-e2e-test-expansion-staging-baselines/34-VERIFICATION.md
  • tests/load/baselines/byo-load-test-plan.md
  • tests/web-e2e/playwright.config.ts
  • tests/web-e2e/tests/batch-download.spec.ts
  • tests/web-e2e/tests/media-preview.spec.ts
  • tests/web-e2e/tests/streaming-playback.spec.ts
  • tests/web-e2e/utils/multi-account-wallet.ts
  • tests/web-e2e/utils/test-files.ts
✅ Files skipped from review due to trivial changes (3)
  • .planning/phases/34-e2e-test-expansion-staging-baselines/34-VERIFICATION.md
  • tests/load/baselines/byo-load-test-plan.md
  • tests/web-e2e/tests/streaming-playback.spec.ts
🚧 Files skipped from review as they are similar to previous changes (5)
  • tests/web-e2e/utils/multi-account-wallet.ts
  • tests/web-e2e/utils/test-files.ts
  • tests/web-e2e/tests/media-preview.spec.ts
  • tests/web-e2e/playwright.config.ts
  • .github/workflows/load-test.yml

Comment thread tests/web-e2e/tests/batch-download.spec.ts Outdated
Prevents stale selection state leaking between serial tests.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 6b5ed854adec

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 36 out of 40 changed files in this pull request and generated 5 comments.

Comment thread tests/web-e2e/utils/cleanup-helpers.ts
Comment thread tests/load/baselines/byo-load-test-plan.md
Comment thread tests/load/baselines/byo-load-test-plan.md
Comment thread .github/workflows/load-test.yml
- byo-load-test-plan.md: clarify timeline of pin success vs ceiling 403s,
  add pinata to protocol table
- todo: add timeline note distinguishing single-client success from
  capacity ceiling 403 failures
- load-test.yml: fail fast if LOAD_TEST_BYO_AUTH_TOKEN secret is missing
  for byo-* scenarios

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 56f2a0194e8b
@FSM1

FSM1 commented Mar 29, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai please review

@FSM1 FSM1 requested a review from Copilot March 29, 2026 14:18
@coderabbitai

coderabbitai Bot commented Mar 29, 2026

Copy link
Copy Markdown

@FSM1 Sure! Triggering another review of PR #392 now.


🧠 Learnings used
Learnt from: FSM1
Repo: FSM1/cipher-box PR: 296
File: packages/sdk/src/client.ts:286-360
Timestamp: 2026-03-20T23:50:55.576Z
Learning: In `packages/sdk/src/client.ts` (`CipherBoxClient`): Concurrent mutations to the same folder (e.g., `createFolder`, `renameItem`, `moveItem`, `deleteItem`, `deleteToBin`) are intentionally not serialized with a per-folder mutex in the SDK. Concurrent safety is provided at the UI layer — buttons/actions are disabled while an operation is in flight. A keyed async mutex/queue per folder IPNS name (and a separate one for bin state) is a known deferred improvement and should not be re-flagged as a regression in this or future PRs (first flagged in PR `#296`).

Learnt from: FSM1
Repo: FSM1/cipher-box PR: 318
File: tests/load/src/scenarios/upload-throughput.test.ts:8-15
Timestamp: 2026-03-22T18:39:53.860Z
Learning: In `tests/load/src/scenarios/*.test.ts` (load test scenarios in FSM1/cipher-box): Load tests are measurement tools, not pass/fail correctness tests. `Promise.allSettled` is used intentionally — partial client completion is expected, and error counts are captured and reported in the metrics JSON via `aggregateAndReport`. Do NOT flag the absence of `expect(failures).toHaveLength(0)` assertions or suggest switching to `Promise.all`. The test should remain green even when some client workloads reject.

Learnt from: FSM1
Repo: FSM1/cipher-box PR: 342
File: docker/docker-compose.staging.yml:66-69
Timestamp: 2026-03-23T23:48:45.109Z
Learning: In FSM1/cipher-box, the `ipfs_staging` volume migration from flatfs to pebbleds (introduced in PR `#342`, `IPFS_PROFILE=server,pebbleds`) is intentionally a manual operation — NOT automated in the deploy workflow. The cutover plan is: spin up a new pebbleds Kubo container alongside the existing flatfs one, validate pinned CIDs against the database, re-pin only active CIDs to the new node, then swap. The inline comment in `docker/docker-compose.staging.yml` (around the `IPFS_PROFILE` env var) documents the volume reset requirement for operators. Do not flag the missing `down -v` step in the deploy workflow as a regression.

Learnt from: FSM1
Repo: FSM1/cipher-box PR: 253
File: tests/e2e-desktop/scripts/test-conflict-detection.ps1:156-157
Timestamp: 2026-03-03T14:55:05.884Z
Learning: In `tests/e2e-desktop/scripts/*.{sh,ps1}` (FUSE E2E tests): Fixed sleep-based waits after file mutations are an inherent limitation of FUSE-mount testing. The FUSE daemon provides no IPC signal or status endpoint to indicate when a debounced IPNS metadata publish completes. Tests use conservative fixed waits (e.g., 8s for initial publish accounting for 1.5s debounce + 10s safety valve, 15s for conflict resolution) and can be increased if CI proves flaky. Eliminating sleep-based waits would require exposing an IPC readiness signal from the FUSE daemon.

Learnt from: FSM1
Repo: FSM1/cipher-box PR: 296
File: .release-please-manifest.json:3-6
Timestamp: 2026-03-20T14:25:00.151Z
Learning: In FSM1/cipher-box, the newly extracted packages `packages/core`, `packages/api-client`, `packages/sdk-core`, and `packages/sdk` are all `private: true` and share the monorepo version (`0.24.2`). Their entries in `.release-please-manifest.json` must match the version declared in their respective `package.json` files (currently `0.24.2`). Do NOT suggest initialising them at `0.1.0` — that would create a manifest/package.json mismatch and break Release Please bump calculations. Only `packages/crypto` and the root `"."` were pre-existing; the new packages simply join the same coupled versioning scheme.

Learnt from: FSM1
Repo: FSM1/cipher-box PR: 318
File: tests/load/src/harness/client-pool.ts:77-80
Timestamp: 2026-03-22T18:39:41.142Z
Learning: In `tests/load/src/harness/client-pool.ts`, the shared `cipherbox/api-client` singleton `setApiClientConfig` is configured once using `clients[0].accessToken` as the `getAccessToken` callback, meaning all SDK-core calls (e.g., `ipnsControllerPublishRecord` via `updateFolderMetadataAndPublish`) authenticate as client 0 regardless of which pool client is making the call. This is a known, pre-existing design gap inherited from the initial web-app extraction of the api-client singleton. It is tracked for resolution in `.planning/todos/pending/2026-03-22-refactor-api-client-from-singleton-to-instance-scoped-axios.md` (refactor orval-generated functions to accept a per-instance axios instance). Do NOT re-flag this as a new issue in future PRs.

Learnt from: FSM1
Repo: FSM1/cipher-box PR: 296
File: apps/web/src/hooks/useDropUpload.ts:63-74
Timestamp: 2026-03-20T14:24:47.508Z
Learning: In `apps/web/src/hooks/useDropUpload.ts`, the divergent parent-folder resolution between the collision-check path (uses `useFolderStore.getState().folders[folderId]` directly) and the upload path (uses `folderId === 'root' ? getRootFolderState(vault, folders) : folders[folderId]`) is pre-existing code moved during the Phase 19.1 SDK extraction refactor (PR `#296`). Consolidating both into a single resolution call is a known deferred improvement — do not flag this as a new regression introduced by the PR.

Learnt from: FSM1
Repo: FSM1/cipher-box PR: 268
File: tests/e2e/tests/recycle-bin.spec.ts:431-446
Timestamp: 2026-03-05T01:50:38.331Z
Learning: In `tests/e2e/tests/recycle-bin.spec.ts` TC08 (`permanent delete of versioned file reclaims all quota`): The secondary quota assertion (`quotaAfter < quotaBefore`) is intentionally a best-effort, loose check. Tightening it to an exact byte delta is explicitly rejected because encryption overhead, IPFS chunking, and pinning-service metadata size variability make deterministic freed-byte calculations unreliable in E2E tests. The primary assertion is that permanent delete completes without crash (the item disappears from the bin); the quota check is only a supplementary signal when the Zustand store is accessible.
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 36 out of 40 changed files in this pull request and generated 1 comment.

Comment thread tests/web-e2e/utils/test-files.ts
Add COMMITTED_FIXTURES set that prevents createTestTextFile,
createTestBinaryFile, createTestImageFile, and createTestMediaFile
from overwriting committed fixture files. Throws early if the
destination name matches any existing fixture.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 721f601d4769
@FSM1

FSM1 commented Mar 29, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai please review.

@coderabbitai

coderabbitai Bot commented Mar 29, 2026

Copy link
Copy Markdown

@FSM1 Sure! I'll kick off a full re-review of PR #392 now, covering all changes across the new E2E specs, cleanup helpers, staging baselines, CI workflow updates, and the removed browser-based load test.


🧠 Learnings used
Learnt from: FSM1
Repo: FSM1/cipher-box PR: 296
File: packages/sdk/src/client.ts:286-360
Timestamp: 2026-03-20T23:50:55.576Z
Learning: In `packages/sdk/src/client.ts` (`CipherBoxClient`): Concurrent mutations to the same folder (e.g., `createFolder`, `renameItem`, `moveItem`, `deleteItem`, `deleteToBin`) are intentionally not serialized with a per-folder mutex in the SDK. Concurrent safety is provided at the UI layer — buttons/actions are disabled while an operation is in flight. A keyed async mutex/queue per folder IPNS name (and a separate one for bin state) is a known deferred improvement and should not be re-flagged as a regression in this or future PRs (first flagged in PR `#296`).

Learnt from: FSM1
Repo: FSM1/cipher-box PR: 296
File: apps/web/src/hooks/useDropUpload.ts:63-74
Timestamp: 2026-03-20T14:24:47.508Z
Learning: In `apps/web/src/hooks/useDropUpload.ts`, the divergent parent-folder resolution between the collision-check path (uses `useFolderStore.getState().folders[folderId]` directly) and the upload path (uses `folderId === 'root' ? getRootFolderState(vault, folders) : folders[folderId]`) is pre-existing code moved during the Phase 19.1 SDK extraction refactor (PR `#296`). Consolidating both into a single resolution call is a known deferred improvement — do not flag this as a new regression introduced by the PR.

Learnt from: FSM1
Repo: FSM1/cipher-box PR: 296
File: .release-please-manifest.json:3-6
Timestamp: 2026-03-20T14:25:00.151Z
Learning: In FSM1/cipher-box, the newly extracted packages `packages/core`, `packages/api-client`, `packages/sdk-core`, and `packages/sdk` are all `private: true` and share the monorepo version (`0.24.2`). Their entries in `.release-please-manifest.json` must match the version declared in their respective `package.json` files (currently `0.24.2`). Do NOT suggest initialising them at `0.1.0` — that would create a manifest/package.json mismatch and break Release Please bump calculations. Only `packages/crypto` and the root `"."` were pre-existing; the new packages simply join the same coupled versioning scheme.

Learnt from: FSM1
Repo: FSM1/cipher-box PR: 342
File: docker/docker-compose.staging.yml:66-69
Timestamp: 2026-03-23T23:48:45.109Z
Learning: In FSM1/cipher-box, the `ipfs_staging` volume migration from flatfs to pebbleds (introduced in PR `#342`, `IPFS_PROFILE=server,pebbleds`) is intentionally a manual operation — NOT automated in the deploy workflow. The cutover plan is: spin up a new pebbleds Kubo container alongside the existing flatfs one, validate pinned CIDs against the database, re-pin only active CIDs to the new node, then swap. The inline comment in `docker/docker-compose.staging.yml` (around the `IPFS_PROFILE` env var) documents the volume reset requirement for operators. Do not flag the missing `down -v` step in the deploy workflow as a regression.

Learnt from: FSM1
Repo: FSM1/cipher-box PR: 0
File: :0-0
Timestamp: 2026-03-27T00:04:37.583Z
Learning: In `apps/api/src/ipns/ipns.service.ts` (`upsertFolderIpns`, lines ~182-288): The "shared child IPNS records become recipient-owned" concern is NOT a vulnerability. (1) For existing shared IPNS records: when no owner `FolderIpns` row is found for `(userId, ipnsName)`, `findActiveWriteShare()` is called; if an active write share exists, the owner's row is fetched via `writeShare.sharerId` — sequence/CID updates always land on the owner's row. Post-revocation `findActiveWriteShare()` returns null, blocking recipient publishes. (2) For new child IPNS records created by a write-share recipient (e.g., new subfolders): these are stored under the recipient's `userId` intentionally because the recipient generated and signed that keypair; post-revocation the recipient loses write access to the parent folder metadata, so orphaned child records have no writable pointer and are non-exploitable. (3) `encryptedIpnsPrivateKey`/`keyEpoch` updates and `enrollFolder()` calls are both gated on `existing.userId === userId`, preventing TEE enrollment overwrites. Do NOT re-flag this as a security regression in future PRs.

Learnt from: FSM1
Repo: FSM1/cipher-box PR: 318
File: tests/load/src/harness/client-pool.ts:77-80
Timestamp: 2026-03-22T18:39:41.142Z
Learning: In `tests/load/src/harness/client-pool.ts`, the shared `cipherbox/api-client` singleton `setApiClientConfig` is configured once using `clients[0].accessToken` as the `getAccessToken` callback, meaning all SDK-core calls (e.g., `ipnsControllerPublishRecord` via `updateFolderMetadataAndPublish`) authenticate as client 0 regardless of which pool client is making the call. This is a known, pre-existing design gap inherited from the initial web-app extraction of the api-client singleton. It is tracked for resolution in `.planning/todos/pending/2026-03-22-refactor-api-client-from-singleton-to-instance-scoped-axios.md` (refactor orval-generated functions to accept a per-instance axios instance). Do NOT re-flag this as a new issue in future PRs.

Learnt from: FSM1
Repo: FSM1/cipher-box PR: 372
File: apps/web/src/hooks/useFileOperations.ts:460-480
Timestamp: 2026-03-26T22:11:32.283Z
Learning: In `apps/web/src/hooks/useFileOperations.ts` (`handleUpdateFile`, `handleAddFile`, `handleAddFiles`): The `reWrapForRecipients()` call is intentionally fire-and-forget (not awaited before `replaceFileInFolder` / `addFileToFolder`). Awaiting it before publish would add latency to every file save/upload. The brief window where share recipients see stale content after an owner update is an accepted architectural tradeoff documented in the writable-shares PoC (Phase 27). Do not flag this as a race condition or access-gap regression in current or future PRs.

Learnt from: FSM1
Repo: FSM1/cipher-box PR: 344
File: .planning/phases/20-vault-migration/20-02-PLAN.md:21-25
Timestamp: 2026-03-24T03:38:10.078Z
Learning: In FSM1/cipher-box `apps/api` and `.planning/`: As of Phase 20 (PR `#344`), the server stores ZERO crypto material by design. Both `encryptedRootFolderKey` and `encryptedRootIpnsPrivateKey` are NULLed on migration via `POST /vault/migrate`. The previously documented permanent DB fallback for `encryptedRootFolderKey` was intentionally removed in gap-closure plans 20-05 and 20-06 after verification confirmed zero non-migrated vaults exist in any environment (staging DB was nuked during Phase 19.2). `REQUIREMENTS.md` and all login/recovery flows have been updated to reflect the zero-crypto-material server state. Do NOT flag nulling of `encryptedRootFolderKey` in migration logic as a missing fallback.

Learnt from: FSM1
Repo: FSM1/cipher-box PR: 253
File: tests/e2e-desktop/scripts/test-conflict-detection.ps1:156-157
Timestamp: 2026-03-03T14:55:05.884Z
Learning: In `tests/e2e-desktop/scripts/*.{sh,ps1}` (FUSE E2E tests): Fixed sleep-based waits after file mutations are an inherent limitation of FUSE-mount testing. The FUSE daemon provides no IPC signal or status endpoint to indicate when a debounced IPNS metadata publish completes. Tests use conservative fixed waits (e.g., 8s for initial publish accounting for 1.5s debounce + 10s safety valve, 15s for conflict resolution) and can be increased if CI proves flaky. Eliminating sleep-based waits would require exposing an IPC readiness signal from the FUSE daemon.

Learnt from: FSM1
Repo: FSM1/cipher-box PR: 268
File: tests/e2e/tests/recycle-bin.spec.ts:431-446
Timestamp: 2026-03-05T01:50:38.331Z
Learning: In `tests/e2e/tests/recycle-bin.spec.ts` TC08 (`permanent delete of versioned file reclaims all quota`): The secondary quota assertion (`quotaAfter < quotaBefore`) is intentionally a best-effort, loose check. Tightening it to an exact byte delta is explicitly rejected because encryption overhead, IPFS chunking, and pinning-service metadata size variability make deterministic freed-byte calculations unreliable in E2E tests. The primary assertion is that permanent delete completes without crash (the item disappears from the bin); the quota check is only a supplementary signal when the Zustand store is accessible.

Learnt from: FSM1
Repo: FSM1/cipher-box PR: 318
File: tests/load/src/scenarios/upload-throughput.test.ts:8-15
Timestamp: 2026-03-22T18:39:53.860Z
Learning: In `tests/load/src/scenarios/*.test.ts` (load test scenarios in FSM1/cipher-box): Load tests are measurement tools, not pass/fail correctness tests. `Promise.allSettled` is used intentionally — partial client completion is expected, and error counts are captured and reported in the metrics JSON via `aggregateAndReport`. Do NOT flag the absence of `expect(failures).toHaveLength(0)` assertions or suggest switching to `Promise.all`. The test should remain green even when some client workloads reject.

Learnt from: FSM1
Repo: FSM1/cipher-box PR: 249
File: apps/api/src/auth/services/auth-method.service.ts:159-194
Timestamp: 2026-03-02T22:32:04.963Z
Learning: In PR `#249` (Tier 2 structural refactoring), pre-existing patterns from moved code (e.g., auth.service.ts → auth-method.service.ts) are intentionally preserved as-is. Behavior changes—such as adding pessimistic locking or changing error handling—are out of scope for structural split PRs and should be tracked as separate follow-up improvements.
✅ Actions performed

Full review triggered.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
tests/web-e2e/utils/test-files.ts (1)

158-168: Enforce “committed source fixture” contract explicitly.

createTestMediaFile sanitizes sourceFixture, but it doesn’t verify that the source is one of the committed fixtures. Adding that check avoids accidental coupling to runtime-generated files.

🔧 Suggested hardening
 export function createTestMediaFile(sourceFixture: string, name?: string): TestBinaryFile {
   const timestamp = Date.now();
   const safeSource = basename(sourceFixture);
+  if (!COMMITTED_FIXTURES.has(safeSource)) {
+    throw new Error(`Unknown committed fixture: ${safeSource}`);
+  }
   const ext = extname(safeSource).replace('.', '') || 'bin';
   const fileName = basename(name || `test-media-${timestamp}.${ext}`);
   if (COMMITTED_FIXTURES.has(fileName)) {
     throw new Error(`Refusing to overwrite committed fixture: ${fileName}`);
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/web-e2e/utils/test-files.ts` around lines 158 - 168, The function
createTestMediaFile currently sanitizes the provided sourceFixture but doesn't
assert that the source is one of the approved committed fixtures; add an
explicit check early in createTestMediaFile to ensure the sanitized safeSource
(basename(sourceFixture)) is contained in the COMMITTED_FIXTURES set and throw a
clear error if not, before resolving fixturePath or reading file stats
(references: createTestMediaFile, safeSource, COMMITTED_FIXTURES, fixturePath,
statSync).
tests/web-e2e/tests/media-preview.spec.ts (1)

110-118: Minor: Redundant visibility assertion after waitFor.

Line 112 already waits for the modal to become visible. The subsequent isVisible() check on line 113 is redundant.

♻️ Suggested simplification
     // Wait for audio player modal -- audio uses a hidden <audio> element
     // with canvas visualization, so we check for the modal container
     await page.locator('.audio-player-modal').waitFor({ state: 'visible', timeout: 30_000 });
-    expect(await page.locator('.audio-player-modal').isVisible()).toBe(true);
+    // Visibility is guaranteed by waitFor above
 
     // Close modal
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/web-e2e/tests/media-preview.spec.ts` around lines 110 - 118, Remove the
redundant visibility assertion: after calling
page.locator('.audio-player-modal').waitFor({ state: 'visible', ... }) there is
no need to call page.locator('.audio-player-modal').isVisible() — delete the
isVisible() expect and keep the waitFor check (the same '.audio-player-modal'
locator and waitFor call remain); ensure the subsequent modal close logic
(page.keyboard.press('Escape') and the waitFor({ state: 'hidden' })) is
unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@tests/web-e2e/baselines/staging-journey-timing.json`:
- Around line 1-19: Add the missing top-level boolean metadata field
"faro_enabled" to this baseline JSON (alongside "captured" and "environment") so
metadata ingestion passes validation; set "faro_enabled" to true for the staging
baseline and ensure it is present as a sibling to "captured", "environment",
"journeys", and "phases".

In `@tests/web-e2e/utils/cleanup-helpers.ts`:
- Around line 14-16: Add an explicit page lifecycle guard in
deleteAccountViaPage before calling page.evaluate to avoid calling evaluate on a
closed page; check page.isClosed() (or equivalent) and return early (or log and
return) when the page is closed so that the try/catch only covers real runtime
errors from evaluate() and not predictable closed-page skips — update the guard
immediately before the page.evaluate(...) invocation in deleteAccountViaPage.

---

Nitpick comments:
In `@tests/web-e2e/tests/media-preview.spec.ts`:
- Around line 110-118: Remove the redundant visibility assertion: after calling
page.locator('.audio-player-modal').waitFor({ state: 'visible', ... }) there is
no need to call page.locator('.audio-player-modal').isVisible() — delete the
isVisible() expect and keep the waitFor check (the same '.audio-player-modal'
locator and waitFor call remain); ensure the subsequent modal close logic
(page.keyboard.press('Escape') and the waitFor({ state: 'hidden' })) is
unchanged.

In `@tests/web-e2e/utils/test-files.ts`:
- Around line 158-168: The function createTestMediaFile currently sanitizes the
provided sourceFixture but doesn't assert that the source is one of the approved
committed fixtures; add an explicit check early in createTestMediaFile to ensure
the sanitized safeSource (basename(sourceFixture)) is contained in the
COMMITTED_FIXTURES set and throw a clear error if not, before resolving
fixturePath or reading file stats (references: createTestMediaFile, safeSource,
COMMITTED_FIXTURES, fixturePath, statSync).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 2a688941-8053-4302-81c5-8da06058482e

📥 Commits

Reviewing files that changed from the base of the PR and between a9604a1 and 07bf3ea.

⛔ Files ignored due to path filters (4)
  • tests/web-e2e/fixtures/files/test-audio.mp3 is excluded by !**/*.mp3
  • tests/web-e2e/fixtures/files/test-document.pdf is excluded by !**/*.pdf
  • tests/web-e2e/fixtures/files/test-video-small.mp4 is excluded by !**/*.mp4
  • tests/web-e2e/fixtures/files/test-video.mp4 is excluded by !**/*.mp4
📒 Files selected for processing (36)
  • .github/workflows/load-test.yml
  • .learnings/2026-03-29-staging-load-test-throttle-bypass.md
  • .planning/ROADMAP.md
  • .planning/STATE.md
  • .planning/phases/34-e2e-test-expansion-staging-baselines/34-01-PLAN.md
  • .planning/phases/34-e2e-test-expansion-staging-baselines/34-01-SUMMARY.md
  • .planning/phases/34-e2e-test-expansion-staging-baselines/34-02-PLAN.md
  • .planning/phases/34-e2e-test-expansion-staging-baselines/34-02-SUMMARY.md
  • .planning/phases/34-e2e-test-expansion-staging-baselines/34-03-PLAN.md
  • .planning/phases/34-e2e-test-expansion-staging-baselines/34-03-SUMMARY.md
  • .planning/phases/34-e2e-test-expansion-staging-baselines/34-04-PLAN.md
  • .planning/phases/34-e2e-test-expansion-staging-baselines/34-04-SUMMARY.md
  • .planning/phases/34-e2e-test-expansion-staging-baselines/34-RESEARCH.md
  • .planning/phases/34-e2e-test-expansion-staging-baselines/34-VERIFICATION.md
  • .planning/todos/pending/2026-03-29-debug-byo-ipfs-register-cid-400-errors-on-staging.md
  • tests/load/baselines/byo-load-test-plan.md
  • tests/load/baselines/staging-byo-capacity-ceiling.json
  • tests/load/baselines/staging-sustained-load.json
  • tests/web-e2e/.gitignore
  • tests/web-e2e/baselines/staging-journey-timing.json
  • tests/web-e2e/playwright.config.ts
  • tests/web-e2e/playwright.load.config.ts
  • tests/web-e2e/tests/batch-download.spec.ts
  • tests/web-e2e/tests/conflict-detection.spec.ts
  • tests/web-e2e/tests/full-workflow.spec.ts
  • tests/web-e2e/tests/journey-timing.spec.ts
  • tests/web-e2e/tests/load-test.spec.ts
  • tests/web-e2e/tests/media-preview.spec.ts
  • tests/web-e2e/tests/mfa-flows.spec.ts
  • tests/web-e2e/tests/recycle-bin.spec.ts
  • tests/web-e2e/tests/search-workflow.spec.ts
  • tests/web-e2e/tests/streaming-playback.spec.ts
  • tests/web-e2e/tests/wallet-login.spec.ts
  • tests/web-e2e/utils/cleanup-helpers.ts
  • tests/web-e2e/utils/multi-account-wallet.ts
  • tests/web-e2e/utils/test-files.ts
💤 Files with no reviewable changes (2)
  • tests/web-e2e/playwright.load.config.ts
  • tests/web-e2e/tests/load-test.spec.ts

Comment thread tests/web-e2e/baselines/staging-journey-timing.json
Comment thread tests/web-e2e/utils/cleanup-helpers.ts
- Add missing faro_enabled field to staging journey timing baseline
- Add page.isClosed() guard in deleteAccountViaPage before evaluate

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: d57187304e9f
@FSM1 FSM1 merged commit 78bef4b into main Mar 29, 2026
25 checks passed
@FSM1 FSM1 deleted the phase-34-e2e-test-expansion-staging-baselines branch March 29, 2026 15:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants