Skip to content

perf: optimize IPFS upload with concurrent pins and pebbleds datastore#342

Merged
FSM1 merged 25 commits into
mainfrom
feat/phase-19.2-ipfs-upload-perf
Mar 24, 2026
Merged

perf: optimize IPFS upload with concurrent pins and pebbleds datastore#342
FSM1 merged 25 commits into
mainfrom
feat/phase-19.2-ipfs-upload-perf

Conversation

@FSM1

@FSM1 FSM1 commented Mar 23, 2026

Copy link
Copy Markdown
Owner

Summary

  • SDK concurrent pin orchestration: uploadFile now uses Promise.allSettled to parallelize file IPNS publish and folder metadata update steps, reducing the sequential pin chain
  • Kubo pebbleds datastore: Docker Compose configs updated to use LSM-tree backed datastore (IPFS_PROFILE=server,pebbleds) for faster concurrent write throughput
  • Performance baselines: Three-point local comparison isolating each optimization's contribution, plus concurrency probe from 1-100 clients

Key findings

Metric Baseline (50 clients) Both optimizations Change
uploadFile p50 14,664ms 13,860ms -5.5%
uploadFile p95 18,734ms 16,302ms -13.0%
uploadFile p99 20,519ms 17,467ms -14.9%
throughput 3.45 ops/s 3.69 ops/s +7.0%

At 75 clients, pebbleds eliminates the failure mode entirely (10 errors → 0, throughput +43.9%).

Critical finding: SDK concurrent pins alone cause a regression at high concurrency — both optimizations must be deployed together.

Staging migration note

Switching to pebbleds requires a fresh IPFS repo. Staging migration plan: parallel cutover with CID validation against DB before re-pinning to new node.

Test plan

  • 4 unit tests for concurrent upload and partial failure handling
  • Concurrency probe at 1/5/10/20/50/75/100 clients
  • Three-point comparison: sequential+flatfs → concurrent+flatfs → concurrent+pebbleds
  • 75-client stress test confirming pebbleds eliminates failure mode
  • Staging deployment with pebbleds datastore migration (post-merge)
  • Prometheus histogram comparison on staging (post-deploy)

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Faster, more reliable uploads via concurrent orchestration and switching IPFS to a pebbleds datastore (local baselines show reduced latency and higher throughput).
  • Reliability

    • Reduced timeouts/errors in high-concurrency stress runs; uploads succeed even when some background publish steps partially fail (logged/warned).
  • Tests

    • Added concurrency and partial-failure validation tests for upload flows.
  • Documentation

    • Phase 19.2 planning, pre/post baselines, validation and verification reports added.

FSM1 and others added 21 commits March 23, 2026 19:27
Entire-Checkpoint: cd99e3a83c8b
Entire-Checkpoint: 7865dece39f3
- Archive upload-throughput and mixed-workload metrics as pre-19.2 baseline JSON
- Document uploadFile p50/p95/p99, server-side latency breakdown, optimization targets
- Source: existing Phase 19 load test results (local API not running at capture time)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 577280bff1b1
- Test 1: Verify batchPublishIpnsRecords and updateFolderMetadataAndPublish run concurrently
- Test 2: Non-critical batch publish failure logs warning, upload succeeds
- Test 3: Critical folder metadata failure throws (already passes)
- Test 4: Both reject, folder error takes priority over batch error

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 285632b23158
- Replace sequential batchPublishIpnsRecords + updateFolderMetadataAndPublish
  with Promise.allSettled for concurrent execution
- Folder metadata failure is critical (throws)
- IPNS batch publish failure is non-critical (logs warning, upload succeeds)
- Saves ~1.73s per upload by overlapping independent pin operations

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 25989fb4017a
…tion plan

- SUMMARY.md with pre-optimization baselines and Promise.allSettled implementation
- STATE.md updated with plan progress and metrics
- ROADMAP.md updated with phase 19.2 plan progress (1/2 complete)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 2350295ee724
- Add IPFS_PROFILE=server,pebbleds to local dev docker-compose.yml
- Update IPFS_PROFILE to server,pebbleds in staging docker-compose.staging.yml
- Add comments explaining volume recreation requirement for datastore migration

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

- Run upload throughput test (5 clients): p50=1.5s, 0 errors, 3.12 ops/s
- Kubo pebbleds datastore confirmed active via API
- Before/after comparison table with percentage changes
- Success criteria analysis (SC1 likely met, SC3 pending staging validation)
- Document environment caveats (local vs staging baseline mismatch)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 5104e672a608
- SUMMARY.md with before/after comparison and success criteria analysis
- STATE.md updated: phase 19.2 complete, 158 plans total
- ROADMAP.md updated with plan progress

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 42767be6f2e2
…ging validation

Entire-Checkpoint: 9617cd6191ba
Replace staging-dependent validation plan with local three-point
comparison: (1) no opts, (2) SDK concurrent pins, (3) SDK + pebbleds.
Same environment + client count across all runs for valid comparison.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 91c9d9b0bf22
- Add PERF-09 definition to Performance Baselines section
- Add PERF-09 to traceability table mapped to Phase 19.2 (Complete)
- Update coverage count from 36 to 37

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 4889ad36c596
- Add 19.2-03-SUMMARY.md documenting requirement registration
- Update STATE.md position to plan 3 of 4
- Update ROADMAP.md with plan progress (3/4 complete)
- Include 19.2-VERIFICATION.md from verifier

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 2fc8ea0ce5dc
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 03e68cad730e
…meguy routing

- Add Run 0 concurrency probe to find stable client count ceiling
- Specify inline env vars (LOAD_TEST_SECRET, THROTTLE_BYPASS_SECRET)
  since vitest does not load dotenv
- Use someguy (192.168.133.114:8190) instead of mock-ipns-routing
- Document exact API .env config requirements

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 93e1ea74f465
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: c660dc8f2284
…tion baselines

- Added concurrency probe table (Run 0) showing 50-client ceiling
- Added three-point results table with SDK delta, pebbleds delta, and total delta
- Documented optimization attribution: concurrent pins alone hurt at 50 clients, pebbleds rescues
- Added definitive SC analysis: SC4 met, SC2 observable, SC1/SC3 not met at 50 clients
- Updated caveats to reflect three-point findings
- Archived all three-point JSON data

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 0a7e10cbd575
- Created 19.2-04-SUMMARY.md documenting concurrency probe and three-point comparison findings
- Updated STATE.md: Phase 19.2 complete (4/4), added synergistic optimization decision
- Updated ROADMAP.md: marked plans 03 and 04 complete, 4/4 plans, phase status Complete

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 566c46040c36
Pebbleds eliminates the failure mode at 75 clients that flatfs
exhibited (10 errors, timeout). Throughput +43.9%, p95 -52.8%,
zero errors. SC3 (>15% throughput) met at 75-client level.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: f95972856ab6
Re-verification: 6/6 must-haves verified. Both gaps closed
(PERF-09 registration + three-point local baselines).

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

coderabbitai Bot commented Mar 23, 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 17 minutes and 0 seconds before requesting another review.

⌛ 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: 5b684a0b-6384-4438-8bd1-2a6237f3003b

📥 Commits

Reviewing files that changed from the base of the PR and between 8e67807 and 5066471.

📒 Files selected for processing (2)
  • .planning/phases/19.2-ipfs-upload-performance-optimization/19.2-RESEARCH.md
  • packages/sdk/src/__tests__/helpers.ts

Walkthrough

Adds Phase 19.2 artifacts and changes: concurrent IPNS/file-folder publish orchestration in CipherBoxClient.uploadFile() (via Promise.allSettled), new SDK event for IPNS partial failures, tests for concurrency/error-prioritization, Docker enablement of Kubo pebbleds datastore, and pre/post optimization baselines and planning docs.

Changes

Cohort / File(s) Summary
Requirements & Roadmap
\.planning/REQUIREMENTS.md, \.planning/ROADMAP.md, \.planning/STATE.md
Registered PERF-09 as Complete, updated traceability and totals, inserted Phase 19.2 into roadmap and bumped last-updated timestamps/state.
Phase 19.2 Planning
\.planning/phases/19.2-ipfs-upload-performance-optimization/*
Added research, validation, verification, four plan docs (19.2-01…04), summaries, and phase-specific todos describing concurrent SDK pin orchestration, pebbleds migration steps, verification criteria, and execution workflows.
Performance Baselines
\.planning/baselines/19.2-pre-optimization-baselines.md, \.planning/baselines/19.2-post-optimization-baselines.md, tests/load/metrics-baseline-pre-19.2.json
Added pre- and post-optimization baseline reports and JSON metrics for load-test comparisons (matched-environment three-point comparison and stress run).
Docker Compose (Kubo pebbleds)
docker/docker-compose.yml, docker/docker-compose.staging.yml
Enabled IPFS_PROFILE=server,pebbleds for ipfs service (documented repo reset requirement) to use pebbleds datastore for concurrent-write optimization.
SDK: Client Logic & Events
packages/sdk/src/client.ts, packages/sdk/src/events.ts
CipherBoxClient.uploadFile() changed to run batchPublishIpnsRecords and updateFolderMetadataAndPublish concurrently via Promise.allSettled; folder-publish failures are critical (throw), IPNS batch failures are non-critical (warn + emit ipns:batchPublishFailed). Added ipns:batchPublishFailed SdkEvent variant.
SDK Tests & Test Helpers
packages/sdk/src/__tests__/client-upload-concurrency.test.ts, packages/sdk/src/__tests__/client-*.test.ts, packages/sdk/src/__tests__/helpers.ts
Added concurrency-focused test suite and shared test helpers; updated existing tests to use shared helpers. Tests assert concurrent invocation ordering, error prioritization, warning logs, and emitted ipns:batchPublishFailed events.
Todos / Misc
.planning/todos/pending/*.md
Added investigation TODOs for mock IPNS routing removal and load-test JWT refresh handling.

Sequence Diagram(s)

sequenceDiagram
    participant Client as CipherBoxClient
    participant IPNS as sdkCore.batchPublishIpnsRecords
    participant Folder as sdkCore.updateFolderMetadataAndPublish
    participant State as InternalState

    rect rgba(200,150,255,0.5)
    Note over Client,State: BEFORE — Sequential execution
    Client->>IPNS: publish file IPNS record
    activate IPNS
    IPNS-->>Client: filePublishResult
    deactivate IPNS
    Client->>Folder: update folder metadata & publish
    activate Folder
    Folder-->>Client: folderPublishResult
    deactivate Folder
    Client->>State: apply results
    end

    rect rgba(150,200,150,0.5)
    Note over Client,State: AFTER — Concurrent execution (Promise.allSettled)
    par Parallel calls
        Client->>IPNS: publish file IPNS record
        activate IPNS
        Client->>Folder: update folder metadata & publish
        activate Folder
    and
        IPNS-->>Client: filePublishResult (fulfill/reject)
        deactivate IPNS
        Folder-->>Client: folderPublishResult (fulfill/reject)
        deactivate Folder
    end
    alt Folder rejects
        Client->>Client: throw folder error (critical)
    else Folder fulfills, IPNS rejects
        Client->>Client: log warning + emit ipns:batchPublishFailed (non-critical)
        Client->>State: apply folderPublishResult
    else Both fulfill
        Client->>State: apply both results
    end
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title clearly and specifically describes the primary change: optimizing IPFS upload performance through concurrent pin orchestration and the pebbleds datastore, matching the main intent and implementation throughout the changeset.

✏️ 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 feat/phase-19.2-ipfs-upload-perf

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.

@codecov

codecov Bot commented Mar 23, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 95.12195% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 50.84%. Comparing base (aefc3b4) to head (5066471).
⚠️ Report is 2 commits behind head on main.

Files with missing lines Patch % Lines
packages/sdk/src/client.ts 95.12% 2 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main     #342      +/-   ##
==========================================
+ Coverage   50.73%   50.84%   +0.11%     
==========================================
  Files         115      114       -1     
  Lines        9227     9252      +25     
  Branches      727      734       +7     
==========================================
+ Hits         4681     4704      +23     
- Misses       4367     4369       +2     
  Partials      179      179              
Flag Coverage Δ
api 83.15% <95.12%> (+0.05%) ⬆️
api-client 83.15% <95.12%> (+0.05%) ⬆️
core 83.15% <95.12%> (+0.05%) ⬆️
crypto 83.15% <95.12%> (+0.05%) ⬆️
sdk 83.15% <95.12%> (+0.05%) ⬆️
sdk-core 83.15% <95.12%> (+0.05%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
packages/sdk/src/events.ts 100.00% <ø> (ø)
packages/sdk/src/client.ts 78.50% <95.12%> (+0.79%) ⬆️

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

…ailed event

- Extract createTestConfig and setupFolder to shared __tests__/helpers.ts
  (was duplicated across 3 test files)
- Add ipns:batchPublishFailed typed event for consumer observability
  (consistent with share:reWrapFailed pattern)
- Replace setTimeout(10) with Promise.resolve() in concurrency test
- Add comment about benign orphaned IPNS record on folder-update failure

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

@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 (1)
packages/sdk/src/__tests__/client-upload-concurrency.test.ts (1)

220-221: Minor: Mock return value doesn't match actual signature.

batchPublishIpnsRecords returns Promise<{ totalSucceeded: number; totalFailed: number }> per the real signature, but the mock resolves with undefined. This works here because the test validates the rejection path, but for consistency:

🔧 Suggested fix for type consistency
-    vi.mocked(sdkCore.batchPublishIpnsRecords).mockResolvedValue(undefined);
+    vi.mocked(sdkCore.batchPublishIpnsRecords).mockResolvedValue({ totalSucceeded: 1, totalFailed: 0 });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/sdk/src/__tests__/client-upload-concurrency.test.ts` around lines
220 - 221, The mock for batchPublishIpnsRecords uses
mockResolvedValue(undefined) but the real signature returns Promise<{
totalSucceeded: number; totalFailed: number }>, so update the test to resolve
with an object matching that shape (e.g., { totalSucceeded: 0, totalFailed: 0 })
when calling vi.mocked(sdkCore.batchPublishIpnsRecords) so the mock matches the
actual function signature; keep
vi.mocked(sdkCore.updateFolderMetadataAndPublish).mockRejectedValue(folderError)
as-is since it’s testing the rejection path.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.planning/phases/19.2-ipfs-upload-performance-optimization/19.2-RESEARCH.md:
- Around line 174-179: Update the Pitfall 1 text to reflect the actual
asymmetric failure policy used in implementation: state that folder metadata
publish is treated as a critical failure (causes upload to fail) while batch
IPNS/file IPNS publish failures are treated as non-critical warnings or retried
according to the logic in packages/sdk/src/client.ts; replace the current
recommendation that "either Promise outcome should fail the upload" with
guidance to use Promise.allSettled for observation but explicitly document that
only folder metadata failure is fatal and batch IPNS failures are tolerated per
the existing prioritized partial-failure handling.

In `@docker/docker-compose.staging.yml`:
- Around line 66-69: The staging compose change enables
IPFS_PROFILE=server,pebbleds but the deploy-staging workflow still runs docker
compose up -d without removing the old ipfs_staging volume, which will break
Kubo on first deploy; update the deploy-staging workflow to run a one-time
migration step that executes docker compose -f docker-compose.staging.yml down
-v (or docker compose down -v) before docker compose up -d when deploying this
change (or add a gated boolean/migration flag like STAGING_IPFS_MIGRATE to run
the down -v only once), and/or add a clear operator note in deployment docs
referencing the ipfs_staging volume and the IPFS_PROFILE change so operators
know to reset the volume before first deploy.

---

Nitpick comments:
In `@packages/sdk/src/__tests__/client-upload-concurrency.test.ts`:
- Around line 220-221: The mock for batchPublishIpnsRecords uses
mockResolvedValue(undefined) but the real signature returns Promise<{
totalSucceeded: number; totalFailed: number }>, so update the test to resolve
with an object matching that shape (e.g., { totalSucceeded: 0, totalFailed: 0 })
when calling vi.mocked(sdkCore.batchPublishIpnsRecords) so the mock matches the
actual function signature; keep
vi.mocked(sdkCore.updateFolderMetadataAndPublish).mockRejectedValue(folderError)
as-is since it’s testing the rejection path.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 6d5f753d-5d20-45b1-81c8-272899157128

📥 Commits

Reviewing files that changed from the base of the PR and between 9d1c5d5 and bc23e46.

📒 Files selected for processing (24)
  • .planning/REQUIREMENTS.md
  • .planning/ROADMAP.md
  • .planning/STATE.md
  • .planning/baselines/19.2-post-optimization-baselines.md
  • .planning/baselines/19.2-pre-optimization-baselines.md
  • .planning/phases/19.2-ipfs-upload-performance-optimization/.gitkeep
  • .planning/phases/19.2-ipfs-upload-performance-optimization/19.2-01-PLAN.md
  • .planning/phases/19.2-ipfs-upload-performance-optimization/19.2-01-SUMMARY.md
  • .planning/phases/19.2-ipfs-upload-performance-optimization/19.2-02-PLAN.md
  • .planning/phases/19.2-ipfs-upload-performance-optimization/19.2-02-SUMMARY.md
  • .planning/phases/19.2-ipfs-upload-performance-optimization/19.2-03-PLAN.md
  • .planning/phases/19.2-ipfs-upload-performance-optimization/19.2-03-SUMMARY.md
  • .planning/phases/19.2-ipfs-upload-performance-optimization/19.2-04-PLAN.md
  • .planning/phases/19.2-ipfs-upload-performance-optimization/19.2-04-SUMMARY.md
  • .planning/phases/19.2-ipfs-upload-performance-optimization/19.2-RESEARCH.md
  • .planning/phases/19.2-ipfs-upload-performance-optimization/19.2-VALIDATION.md
  • .planning/phases/19.2-ipfs-upload-performance-optimization/19.2-VERIFICATION.md
  • .planning/todos/pending/2026-03-23-investigate-removal-of-mock-ipns-routing-layer.md
  • .planning/todos/pending/2026-03-23-load-tests-should-handle-401s-with-token-refresh.md
  • docker/docker-compose.staging.yml
  • docker/docker-compose.yml
  • packages/sdk/src/__tests__/client-upload-concurrency.test.ts
  • packages/sdk/src/client.ts
  • tests/load/metrics-baseline-pre-19.2.json

Comment thread docker/docker-compose.staging.yml

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

This PR targets improved uploadFile performance by parallelizing independent IPNS/folder publish steps in the SDK and increasing Kubo write throughput via the pebbleds datastore profile, with supporting baselines, planning artifacts, and tests.

Changes:

  • Update CipherBoxClient.uploadFile() to run file IPNS batch publish concurrently with folder metadata update using Promise.allSettled.
  • Switch local + staging Docker Compose IPFS nodes to IPFS_PROFILE=server,pebbleds (fresh repo required).
  • Add unit tests and capture/report pre/post performance baselines and Phase 19.2 planning/verification docs.

Reviewed changes

Copilot reviewed 27 out of 28 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
tests/load/metrics-baseline-pre-19.2.json Adds archived pre-optimization load-test metrics JSON for comparison.
packages/sdk/src/events.ts Adds ipns:batchPublishFailed SDK event type.
packages/sdk/src/client.ts Implements concurrent IPNS batch publish + folder publish in uploadFile() with partial-failure handling.
packages/sdk/src/tests/helpers.ts Adds shared test helpers (config + folder setup).
packages/sdk/src/tests/client.test.ts Refactors tests to use shared helpers.
packages/sdk/src/tests/client-upload-concurrency.test.ts Adds new tests covering concurrency + partial failure behavior for uploadFile().
packages/sdk/src/tests/client-extended.test.ts Refactors extended tests to use shared helpers.
docker/docker-compose.yml Enables IPFS_PROFILE=server,pebbleds for local IPFS service with migration note.
docker/docker-compose.staging.yml Enables IPFS_PROFILE: server,pebbleds for staging IPFS service with migration note.
.planning/todos/pending/2026-03-23-load-tests-should-handle-401s-with-token-refresh.md Adds a todo for improving load-test auth refresh handling.
.planning/todos/pending/2026-03-23-investigate-removal-of-mock-ipns-routing-layer.md Adds a todo to evaluate removing the mock IPNS routing layer.
.planning/phases/19.2-ipfs-upload-performance-optimization/19.2-VERIFICATION.md Adds Phase 19.2 verification report + remaining human checks.
.planning/phases/19.2-ipfs-upload-performance-optimization/19.2-VALIDATION.md Adds Phase 19.2 validation strategy document.
.planning/phases/19.2-ipfs-upload-performance-optimization/19.2-RESEARCH.md Adds detailed research write-up + architecture/pitfalls for the perf work.
.planning/phases/19.2-ipfs-upload-performance-optimization/19.2-04-SUMMARY.md Adds summary of matched-environment three-point comparison.
.planning/phases/19.2-ipfs-upload-performance-optimization/19.2-04-PLAN.md Adds execution plan for three-point local baseline methodology.
.planning/phases/19.2-ipfs-upload-performance-optimization/19.2-03-SUMMARY.md Adds summary for PERF-09 requirements registration gap closure.
.planning/phases/19.2-ipfs-upload-performance-optimization/19.2-03-PLAN.md Adds plan to register PERF-09 into REQUIREMENTS.md.
.planning/phases/19.2-ipfs-upload-performance-optimization/19.2-02-SUMMARY.md Adds summary of pebbleds adoption + post-optimization baselines capture.
.planning/phases/19.2-ipfs-upload-performance-optimization/19.2-02-PLAN.md Adds plan to switch Kubo datastore + capture baselines.
.planning/phases/19.2-ipfs-upload-performance-optimization/19.2-01-SUMMARY.md Adds summary of concurrent pins change + baseline capture.
.planning/phases/19.2-ipfs-upload-performance-optimization/19.2-01-PLAN.md Adds plan for baseline capture + concurrent pins implementation.
.planning/phases/19.2-ipfs-upload-performance-optimization/.gitkeep Ensures phase directory exists in git.
.planning/baselines/19.2-pre-optimization-baselines.md Adds pre-optimization baseline report.
.planning/baselines/19.2-post-optimization-baselines.md Adds post-optimization baseline report including three-point comparison.
.planning/STATE.md Updates current planning state to reflect Phase 19.2 completion.
.planning/ROADMAP.md Inserts Phase 19.2 and updates progress table.
.planning/REQUIREMENTS.md Registers PERF-09 and updates traceability + coverage counts.

Comment thread packages/sdk/src/client.ts
Comment thread .planning/baselines/19.2-post-optimization-baselines.md Outdated
Comment thread .planning/ROADMAP.md Outdated
Comment thread packages/sdk/src/client.ts
Comment thread packages/sdk/src/client.ts
- Normalize batchResult.reason to Error before emitting event (Copilot)
- Check batchResult.value.totalFailed for partial publish failures (Copilot)
- Fix ROADMAP.md progress table column alignment (Copilot)
- Fix post-optimization baselines SDK description accuracy (Copilot)
- Update RESEARCH.md pitfall text to match asymmetric failure policy (CodeRabbit)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 2c144ac654c4
@FSM1 FSM1 requested a review from Copilot March 23, 2026 23:51

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 27 out of 28 changed files in this pull request and generated 3 comments.

Comment thread packages/sdk/src/__tests__/client-upload-concurrency.test.ts
Comment thread packages/sdk/src/__tests__/client-upload-concurrency.test.ts Outdated
Comment thread packages/sdk/src/client.ts
- Return { totalSucceeded, totalFailed } from batchPublishIpnsRecords
  mocks to match real function signature
- Add test for batchResult.value.totalFailed > 0 partial failure path

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

@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.

♻️ Duplicate comments (1)
.planning/phases/19.2-ipfs-upload-performance-optimization/19.2-RESEARCH.md (1)

117-130: ⚠️ Potential issue | 🟡 Minor

Unify examples with the documented Promise.allSettled failure contract.

Line 117 and Line 227 still show Promise.all-style guidance, which conflicts with the same file’s pitfall policy (folder failure = critical, batch IPNS failure = non-critical). This can reintroduce the wrong implementation pattern.

🛠️ Suggested doc fix
-// AFTER: concurrent
-const [, publishResult] = await Promise.all([
-  sdkCore.batchPublishIpnsRecords([uploadResult.ipnsRecord], this.ctx),
-  sdkCore.updateFolderMetadataAndPublish({
+// AFTER: concurrent with prioritized failure handling
+const [batchResult, folderResult] = await Promise.allSettled([
+  sdkCore.batchPublishIpnsRecords([uploadResult.ipnsRecord], this.ctx),
+  sdkCore.updateFolderMetadataAndPublish({
     children: updatedChildren,
     folderKey: folder.folderKey,
     ipnsPrivateKey: folder.ipnsKeypair.privateKey,
     ipnsName: folderIpnsName,
     sequenceNumber: folder.sequenceNumber,
     ctx: this.ctx,
   }),
 ]);
-const { newSequenceNumber } = publishResult;
+if (folderResult.status === 'rejected') throw folderResult.reason;
+if (batchResult.status === 'rejected') {
+  console.warn('[SDK] File IPNS batch publish failed:', batchResult.reason);
+}
+const { newSequenceNumber } = folderResult.value;
#!/bin/bash
# Verify implementation and docs are aligned on allSettled + prioritized handling.

set -euo pipefail

echo "== Locate CipherBoxClient.uploadFile implementation =="
fd client.ts packages sdk src 2>/dev/null || true
rg -n -C3 'uploadFile\s*\(' packages/sdk/src/client.ts

echo
echo "== Check Promise API used in implementation =="
rg -n -C4 'Promise\.allSettled|Promise\.all' packages/sdk/src/client.ts

echo
echo "== Check research doc examples for Promise API usage =="
rg -n -C3 'Promise\.allSettled|Promise\.all' .planning/phases/19.2-ipfs-upload-performance-optimization/19.2-RESEARCH.md

echo
echo "== Check prioritized failure handling language in research doc =="
rg -n -C2 'folder metadata publish failure.*critical|batch publish failure.*non-critical|warn \+ emit event' \
  .planning/phases/19.2-ipfs-upload-performance-optimization/19.2-RESEARCH.md

Based on learnings, packages/sdk/src/client.ts intentionally uses prioritized partial-failure handling (folder failure critical, batch IPNS failure non-critical).

Also applies to: 227-250

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.planning/phases/19.2-ipfs-upload-performance-optimization/19.2-RESEARCH.md
around lines 117 - 130, The doc examples still show Promise.all usage; change
them to Promise.allSettled for the concurrent publish so the code and pitfall
policy align: call Promise.allSettled on [sdkCore.batchPublishIpnsRecords(...),
sdkCore.updateFolderMetadataAndPublish(...)], inspect the results array by
status, treat the updateFolderMetadataAndPublish result (the folder publish) as
critical—if it is rejected, surface/throw the error and stop; treat the
batchPublishIpnsRecords result as non‑critical—log/warn and emit the non‑fatal
event if it failed but continue and use the folder publish output
(newSequenceNumber) when fulfilled (refer to sdkCore.batchPublishIpnsRecords,
sdkCore.updateFolderMetadataAndPublish, and publishResult/batchResult in the
example).
🧹 Nitpick comments (2)
packages/sdk/src/__tests__/helpers.ts (1)

28-50: Harden setupFolder against shared-object aliasing and time nondeterminism.

Right now, returned child can alias the same object stored in children, and repeated Date.now() calls reduce reproducibility. A tiny refactor makes test fixtures more stable.

Proposed refactor
-export function setupFolder(client: CipherBoxClient, ipnsName = 'folder-ipns') {
+export function setupFolder(
+  client: CipherBoxClient,
+  ipnsName = 'folder-ipns',
+  now = Date.now()
+) {
   const child = {
     type: 'file' as const,
     id: 'file1',
     name: 'test.txt',
     fileMetaIpnsName: 'k51file',
     ipnsPrivateKeyEncrypted: 'abc',
-    createdAt: Date.now(),
-    modifiedAt: Date.now(),
+    createdAt: now,
+    modifiedAt: now,
   };
   client.getFolderTree().set(ipnsName, {
     ipnsName,
     folderKey: new Uint8Array(32).fill(1),
     ipnsKeypair: {
       publicKey: new Uint8Array(32).fill(2),
       privateKey: new Uint8Array(64).fill(3),
     },
     sequenceNumber: 1n,
-    children: [child],
+    children: [{ ...child }],
     metadata: null,
-    lastLoadedAt: Date.now(),
+    lastLoadedAt: now,
   });
-  return child;
+  return { ...child };
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/sdk/src/__tests__/helpers.ts` around lines 28 - 50, The setupFolder
helper currently stores the same child object into
client.getFolderTree().set(...) and returns it and makes multiple Date.now()
calls; to harden against aliasing and nondeterminism create a single timestamp
const (e.g. const now = Date.now()) and use it for createdAt, modifiedAt and
lastLoadedAt, and insert a defensive clone of the child into the folder's
children (e.g. copy primitive fields and new Uint8Array copies for
folderKey/ipnsKeypair) while returning a separate instance (or clone) so the
returned object does not alias the stored children; update setupFolder,
references to child, folderKey and ipnsKeypair accordingly.
.planning/phases/19.2-ipfs-upload-performance-optimization/19.2-RESEARCH.md (1)

13-14: Refresh recommendation text to reflect final Phase 19.2 rollout guidance.

Line 13 and Line 305 still frame pebbleds as conditional (“if needed”), but this phase’s validated outcome is that concurrent pins alone can regress under high concurrency and should be paired with pebbleds for net benefit.

As per coding guidelines in .planning/ROADMAP.md, success criteria should stay aligned with “concurrent pin orchestration + pebbleds” (not concurrent pins alone).

Also applies to: 305-306

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.planning/phases/19.2-ipfs-upload-performance-optimization/19.2-RESEARCH.md
around lines 13 - 14, Update the Phase 19.2 recommendation text so the primary
recommendation reads that the validated rollout requires "concurrent pin
orchestration + pebbleds" (i.e., pair concurrent pin orchestration in the SDK
client with swapping the Kubo datastore to pebbleds) rather than presenting
pebbleds as conditional; edit the block currently at Line 13 and the repeated
guidance at Lines 305–306 in
.planning/phases/19.2-ipfs-upload-performance-optimization/19.2-RESEARCH.md to
reflect this final rollout guidance and ensure the success criteria align with
the ROADMAP.md requirement of "concurrent pin orchestration + pebbleds."
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In @.planning/phases/19.2-ipfs-upload-performance-optimization/19.2-RESEARCH.md:
- Around line 117-130: The doc examples still show Promise.all usage; change
them to Promise.allSettled for the concurrent publish so the code and pitfall
policy align: call Promise.allSettled on [sdkCore.batchPublishIpnsRecords(...),
sdkCore.updateFolderMetadataAndPublish(...)], inspect the results array by
status, treat the updateFolderMetadataAndPublish result (the folder publish) as
critical—if it is rejected, surface/throw the error and stop; treat the
batchPublishIpnsRecords result as non‑critical—log/warn and emit the non‑fatal
event if it failed but continue and use the folder publish output
(newSequenceNumber) when fulfilled (refer to sdkCore.batchPublishIpnsRecords,
sdkCore.updateFolderMetadataAndPublish, and publishResult/batchResult in the
example).

---

Nitpick comments:
In @.planning/phases/19.2-ipfs-upload-performance-optimization/19.2-RESEARCH.md:
- Around line 13-14: Update the Phase 19.2 recommendation text so the primary
recommendation reads that the validated rollout requires "concurrent pin
orchestration + pebbleds" (i.e., pair concurrent pin orchestration in the SDK
client with swapping the Kubo datastore to pebbleds) rather than presenting
pebbleds as conditional; edit the block currently at Line 13 and the repeated
guidance at Lines 305–306 in
.planning/phases/19.2-ipfs-upload-performance-optimization/19.2-RESEARCH.md to
reflect this final rollout guidance and ensure the success criteria align with
the ROADMAP.md requirement of "concurrent pin orchestration + pebbleds."

In `@packages/sdk/src/__tests__/helpers.ts`:
- Around line 28-50: The setupFolder helper currently stores the same child
object into client.getFolderTree().set(...) and returns it and makes multiple
Date.now() calls; to harden against aliasing and nondeterminism create a single
timestamp const (e.g. const now = Date.now()) and use it for createdAt,
modifiedAt and lastLoadedAt, and insert a defensive clone of the child into the
folder's children (e.g. copy primitive fields and new Uint8Array copies for
folderKey/ipnsKeypair) while returning a separate instance (or clone) so the
returned object does not alias the stored children; update setupFolder,
references to child, folderKey and ipnsKeypair accordingly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 69c7110d-b0bf-4cba-9e7e-4471eef26b6b

📥 Commits

Reviewing files that changed from the base of the PR and between bc23e46 and 8e67807.

📒 Files selected for processing (9)
  • .planning/ROADMAP.md
  • .planning/baselines/19.2-post-optimization-baselines.md
  • .planning/phases/19.2-ipfs-upload-performance-optimization/19.2-RESEARCH.md
  • packages/sdk/src/__tests__/client-extended.test.ts
  • packages/sdk/src/__tests__/client-upload-concurrency.test.ts
  • packages/sdk/src/__tests__/client.test.ts
  • packages/sdk/src/__tests__/helpers.ts
  • packages/sdk/src/client.ts
  • packages/sdk/src/events.ts
✅ Files skipped from review due to trivial changes (5)
  • packages/sdk/src/tests/client-extended.test.ts
  • packages/sdk/src/events.ts
  • .planning/ROADMAP.md
  • packages/sdk/src/client.ts
  • packages/sdk/src/tests/client-upload-concurrency.test.ts

- Update RESEARCH.md examples from Promise.all to Promise.allSettled
  with prioritized failure handling (CodeRabbit duplicate)
- Update recommendation text to reflect validated finding: concurrent
  pins require pebbleds for net benefit (CodeRabbit nitpick)
- Harden setupFolder helper against object aliasing and timestamp
  nondeterminism (CodeRabbit nitpick)

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

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 27 out of 28 changed files in this pull request and generated 1 comment.

Comment thread packages/sdk/src/client.ts
@FSM1 FSM1 merged commit 8f8f03f into main Mar 24, 2026
24 checks passed
@FSM1 FSM1 deleted the feat/phase-19.2-ipfs-upload-perf branch March 24, 2026 00:19
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