Skip to content

fix(api,desktop): fix sequence number mismatch in cached IPNS resolves#449

Merged
FSM1 merged 10 commits into
mainfrom
fix/desktop-e2e-sequence-mismatch
Apr 6, 2026
Merged

fix(api,desktop): fix sequence number mismatch in cached IPNS resolves#449
FSM1 merged 10 commits into
mainfrom
fix/desktop-e2e-sequence-mismatch

Conversation

@FSM1

@FSM1 FSM1 commented Apr 4, 2026

Copy link
Copy Markdown
Owner

Summary

  • Fix parseCachedRecord returning stale sequence number from signed record bytes instead of the DB column
  • Seed FUSE PublishCoordinator cache with sequence numbers from pre-populate resolves

Root cause

The desktop E2E "Persistent conflict" failure was caused by parseCachedRecord parsing the signedRecord bytes and returning the embedded sequence (0, the client's pre-increment value), while the DB column had the correct value (1). This caused the FUSE client's resolve_sequence to return 0, leading to a 409 conflict on the next publish.

Changes

apps/api/src/ipns/ipns.service.tsparseCachedRecord now uses cached.sequenceNumber (DB column) as authoritative, overriding the value parsed from signed record bytes.

apps/desktop/src-tauri/src/fuse/mod.rs — Capture sequence numbers from IPNS resolves during FUSE mount pre-population and seed the PublishCoordinator cache, preventing redundant resolves on first write.

Test plan

  • Full desktop E2E suite passed locally (21 tests, 0 failures)
  • 833 API unit tests pass
  • No IPNS sequence conflicts in desktop logs

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes

    • Preserve authoritative IPNS CID/sequence from cache; tolerate deprecated protobuf group encodings; remove pending publish entries when items are deleted or overwritten; drain upload completions during directory reads.
  • Behavior Changes

    • Signature verification failures during IPNS resolution now warn and do not block resolution.
    • Seed initial publish state from IPNS sequence info during filesystem pre-population.
  • Tests

    • Extended end-to-end polling windows; updated IPNS parser tests; added cache-fallback resolving test.
  • Chores

    • Consolidated CI failure-log collection and upload; redirect API startup logs into runner temp.

Two fixes for the desktop E2E "Persistent conflict" regression:

1. API: parseCachedRecord now uses the DB column's sequenceNumber as
   authoritative instead of parsing it from the signedRecord bytes.
   The record bytes contain the client's pre-increment value (e.g. 0
   on first publish), while the DB column is always incremented by
   upsertFolderIpns (to 1). Using the record's value caused resolve
   to return seq 0, leading to 409 conflicts on the next publish.

2. Desktop: Seed PublishCoordinator cache with sequence numbers from
   the IPNS resolves during FUSE mount pre-population. Previously
   the cache was empty, forcing a redundant resolve on first write
   that could race with other operations.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 2b690f04c0ad
Copilot AI review requested due to automatic review settings April 4, 2026 00:47
@coderabbitai

coderabbitai Bot commented Apr 4, 2026

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 6df27282-a88c-41de-85da-9c00f7bae6a2

📥 Commits

Reviewing files that changed from the base of the PR and between fcc0ddc and a02c83a.

📒 Files selected for processing (2)
  • tests/desktop-e2e/scripts/test-round-trip.ps1
  • tests/desktop-e2e/scripts/test-round-trip.sh
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/desktop-e2e/scripts/test-round-trip.sh

Walkthrough

CI now captures staged logs on failure; API and web IPNS handling favor DB-stored CID/sequence numbers when falling back to cached signed-records while retaining parsed signature fields; protobuf group wire types are skipped (not erroring); desktop FUSE seeds initial IPNS sequences and drains upload completions; E2E polling windows were lengthened.

Changes

Cohort / File(s) Summary
CI/CD workflow
.github/workflows/desktop-e2e.yml
Redirect API stdout/stderr into $RUNNER_TEMP/api.log; on failure copy multiple log sources into failure-logs/ (with `
API IPNS service & tests
apps/api/src/ipns/ipns.service.ts, apps/api/src/ipns/ipns.service.spec.ts
When delegated routing returns null, preserve parsed signature fields from signedRecord but overwrite cid/sequenceNumber with DB latestCid/sequenceNumber; added test covering this fallback.
IPNS protobuf parser & its test
apps/api/src/ipns/ipns-record-parser.ts, apps/api/src/ipns/ipns-record-parser.spec.ts
Extended parser to skip deprecated group wire-type (3) by scanning nested groups (depth tracking); top-level end-group (4) is now an explicit error; test updated to expect successful parse and value extraction.
Web IPNS handling
apps/web/src/services/ipns.service.ts
Signature verification and derived-name/public-key checks are wrapped in try/catch; verification failures are logged and mark signatureVerified = false instead of throwing.
Desktop FUSE pre-population & publish coordinator
apps/desktop/src-tauri/src/fuse/mod.rs
IPNS resolution results include sequence_number: u64; collect (ipns_name, sequence_number) pairs during pre-population and seed PublishCoordinator via record_publish(name, seq) before mounting (logged).
FUSE upload completions & publish-queue cleanup
crates/fuse/src/dir_ops.rs, crates/fuse/src/write_ops.rs, crates/fuse/src/platform/windows/write_ops.rs
handle_readdir now drains upload completions at readdir start; deletions/renames remove inode IDs from fs.publish_queue before removing from fs.inodes to avoid pending-publish errors.
E2E tests — polling & FUSE flushes
tests/desktop-e2e/scripts/test-round-trip.ps1, tests/desktop-e2e/scripts/test-round-trip.sh
Polling attempts doubled (12→24) across multiple verification loops; added short sleeps and best-effort ls/stat calls after FUSE writes to encourage background upload delivery; failure messages updated to reflect longer windows.

Sequence Diagram(s)

sequenceDiagram
    actor Mount as "Mount (tauri)"
    participant Resolver as "IPNS Resolver / API"
    participant Prepop as "Pre-populator"
    participant PubCoord as "PublishCoordinator"

    Mount->>Resolver: resolve IPNS for root and subfolders
    Note right of Resolver: returns (data, path, sequence_number)
    Resolver-->>Mount: (data, path, sequence_number)
    Mount->>Prepop: collect (ipns_name, sequence_number) pairs
    Prepop->>PubCoord: record_publish(name, sequence_number) for each pair
    PubCoord-->>Prepop: ack
    Prepop-->>Mount: pre-population complete
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 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 title directly and accurately summarizes the main fix: addressing a sequence number mismatch in cached IPNS resolves, which is the core issue described in the PR objectives.
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 docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/desktop-e2e-sequence-mismatch

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.

…workspace

upload-artifact@v7 requires files within the repo root. On Windows,
the desktop log is in RUNNER_TEMP (D:\a\_temp\) which is outside the
repo. Copy all logs into a failure-logs/ directory before uploading.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 2d0d04e68084
@github-actions github-actions Bot added release:api:fix Patch version bump (bug fix) for api release:desktop:fix Patch version bump (bug fix) for desktop release:sdk-core:fix Patch version bump (bug fix) for sdk-core release:sdk:fix Patch version bump (bug fix) for sdk release:web:fix Patch version bump (bug fix) for web release:cipherbox-fuse:fix Patch version bump (bug fix) for cipherbox-fuse release:cipherbox-sdk:fix Patch version bump (bug fix) for cipherbox-sdk release:tee-worker:fix Patch version bump (bug fix) for tee-worker labels Apr 4, 2026
@github-actions

github-actions Bot commented Apr 4, 2026

Copy link
Copy Markdown
Contributor

Release Preview

Package Bump Label Source
api patch release:api:fix Direct (fix commit)
cipherbox-fuse patch release:cipherbox-fuse:fix Direct (fix commit)
cipherbox-sdk patch release:cipherbox-sdk:fix Cascade (api patch)
desktop minor release:desktop:fix Direct (fix commit)
sdk patch release:sdk:fix Cascade (api patch)
sdk-core patch release:sdk-core:fix Cascade (api patch)
tee-worker patch release:tee-worker:fix Cascade (sdk-core patch)
web minor release:web:fix Direct (fix commit)

Cascade Details

  • api patch -> sdk-core patch (direct dependency)
  • api patch -> sdk patch (direct dependency)
  • api patch -> cipherbox-sdk patch (direct dependency)
  • sdk-core patch -> tee-worker patch (direct dependency)

@codecov

codecov Bot commented Apr 4, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 15.78947% with 48 lines in your changes missing coverage. Please review.
✅ Project coverage is 71.57%. Comparing base (9b80833) to head (a02c83a).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
apps/desktop/src-tauri/src/fuse/mod.rs 0.00% 25 Missing ⚠️
apps/api/src/ipns/ipns-record-parser.ts 17.85% 20 Missing and 3 partials ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main     #449      +/-   ##
==========================================
+ Coverage   62.43%   71.57%   +9.13%     
==========================================
  Files         135      114      -21     
  Lines       10130     7261    -2869     
  Branches     1067     1081      +14     
==========================================
- Hits         6325     5197    -1128     
+ Misses       3584     1840    -1744     
- Partials      221      224       +3     
Flag Coverage Δ
api 84.67% <28.12%> (-0.33%) ⬇️
api-client 84.67% <28.12%> (-0.33%) ⬇️
core 84.67% <28.12%> (-0.33%) ⬇️
crypto 84.67% <28.12%> (-0.33%) ⬇️
desktop 14.22% <0.00%> (-17.01%) ⬇️
sdk 84.67% <28.12%> (-0.33%) ⬇️
sdk-core 84.67% <28.12%> (-0.33%) ⬇️

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

Files with missing lines Coverage Δ
apps/api/src/ipns/ipns.service.ts 88.09% <100.00%> (+0.17%) ⬆️
apps/api/src/ipns/ipns-record-parser.ts 67.50% <17.85%> (-28.66%) ⬇️
apps/desktop/src-tauri/src/fuse/mod.rs 12.95% <0.00%> (+12.95%) ⬆️

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

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

Fixes IPNS sequence-number conflicts caused by cached resolve responses returning a stale sequence number, and improves desktop FUSE mount behavior by capturing sequence numbers during pre-population for later publish coordination.

Changes:

  • API: parseCachedRecord now treats the DB sequenceNumber column as authoritative when returning cached resolve results.
  • Desktop: FUSE mount pre-population now parses sequence_number from resolve responses and seeds the PublishCoordinator sequence cache.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.

File Description
apps/api/src/ipns/ipns.service.ts Overrides cached resolve sequence numbers with the DB column to avoid stale values parsed from signed record bytes.
apps/desktop/src-tauri/src/fuse/mod.rs Tracks sequence numbers during root/subfolder pre-populate resolves and seeds the publish coordinator cache.

Comment thread apps/desktop/src-tauri/src/fuse/mod.rs
Comment thread apps/desktop/src-tauri/src/fuse/mod.rs
Comment thread apps/api/src/ipns/ipns.service.ts Outdated
Comment thread apps/api/src/ipns/ipns.service.ts Outdated

@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/desktop-e2e.yml:
- Line 507: The cp command copying apps/api/*.log is likely a no-op because the
API logs to stdout/stderr rather than files; replace that behavior by
redirecting the API startup output to a known file and copy that file into
failure-logs instead. Concretely, update the workflow step that runs the API to
tee or redirect its stdout/stderr to a persistent path (e.g.,
$RUNNER_TEMP/api.log) and change/remove the existing cp apps/api/*.log
failure-logs/ invocation so the workflow instead copies $RUNNER_TEMP/api.log (or
both) into failure-logs to ensure API-side logs are collected.
🪄 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: 29e8e072-66c7-4d47-b73f-efb51100a28d

📥 Commits

Reviewing files that changed from the base of the PR and between 9b80833 and 8c2c326.

📒 Files selected for processing (3)
  • .github/workflows/desktop-e2e.yml
  • apps/api/src/ipns/ipns.service.ts
  • apps/desktop/src-tauri/src/fuse/mod.rs

Comment thread .github/workflows/desktop-e2e.yml Outdated
…eprecated protobuf wire types

Signature verification in resolveIpnsRecord now logs warnings instead of
throwing, preventing vault init and folder loading from crashing when the
API returns signature data that doesn't verify due to protobuf parser
inconsistencies. The IPNS record parser now gracefully skips deprecated
wire types 3/4 (start/end group) instead of throwing.

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

@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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/web/src/services/ipns.service.ts (1)

173-210: ⚠️ Potential issue | 🟠 Major

Don’t return a usable record after an explicit signature/key mismatch.

At Line 173 this turns resolveIpnsRecord() into a fail-open path: invalid signatures and pubKeyipnsName mismatches are only logged, then the function still returns a non-null record. The current web callers in apps/web/src/services/vault-settings.service.ts (Lines 35-60 and Lines 105-125) and apps/web/src/services/file-metadata.service.ts (Lines 315-335) do not inspect signatureVerified, so they will silently trust the returned cid / sequenceNumber. That regresses the client-side authenticity check and also diverges from packages/sdk-core/src/ipns/index.ts, which still throws on the same conditions. If parser inconsistencies need a temporary workaround, keep the missing-signature case non-fatal, but continue to reject explicit cryptographic failures until all callers are updated.

Based on learnings: client verifies Ed25519 signature + pubKey-to-ipnsName binding on resolveRecord as a current mitigation.

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

In `@apps/web/src/services/ipns.service.ts` around lines 173 - 210, The
resolveIpnsRecord implementation currently logs but returns a usable record on
explicit crypto failures; change it so that when verifyIpnsSignature returns
false or deriveIpnsName does not match ipnsName the function rejects/throws (or
returns null/undefined) instead of returning a record with
signatureVerified=false; keep the existing non-fatal behavior only for the
"missing signature/pubKey" branch (leave the logger and continue returning
null/empty), but for the explicit failure paths in resolveIpnsRecord
(references: verifyIpnsSignature, deriveIpnsName, signatureVerified) immediately
abort and return an error/value that callers must handle to avoid silently
trusting cid/sequenceNumber.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/api/src/ipns/ipns-record-parser.ts`:
- Around line 113-134: In the wireType === 3 group-skip block in
ipns-record-parser.ts (the loop that uses variables pos, buf, depth and calls
readVarint), add explicit bounds checks before advancing pos for each inner
branch: ensure pos + 4 and pos + 8 are within buf.length before adding 4/8, and
ensure np2 + Number(len) <= buf.length before setting pos = np2 + Number(len);
throw a parsing error if any check fails. After the while loop, verify depth ===
0 and throw if not (to fail closed on unterminated start-group). Also when
encountering a top-level wireType === 4 (end group) outside a group, do not
silently skip — reject by throwing a parsing error. Use the existing readVarint,
pos, buf, depth, innerWire, np/np2, and len identifiers to locate and implement
these checks.

---

Outside diff comments:
In `@apps/web/src/services/ipns.service.ts`:
- Around line 173-210: The resolveIpnsRecord implementation currently logs but
returns a usable record on explicit crypto failures; change it so that when
verifyIpnsSignature returns false or deriveIpnsName does not match ipnsName the
function rejects/throws (or returns null/undefined) instead of returning a
record with signatureVerified=false; keep the existing non-fatal behavior only
for the "missing signature/pubKey" branch (leave the logger and continue
returning null/empty), but for the explicit failure paths in resolveIpnsRecord
(references: verifyIpnsSignature, deriveIpnsName, signatureVerified) immediately
abort and return an error/value that callers must handle to avoid silently
trusting cid/sequenceNumber.
🪄 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: c36c36fc-5b0a-41d4-9b47-d658eaa729b7

📥 Commits

Reviewing files that changed from the base of the PR and between 8c2c326 and 30c96ce.

📒 Files selected for processing (3)
  • apps/api/src/ipns/ipns-record-parser.spec.ts
  • apps/api/src/ipns/ipns-record-parser.ts
  • apps/web/src/services/ipns.service.ts

Comment thread apps/api/src/ipns/ipns-record-parser.ts
FSM1 and others added 2 commits April 5, 2026 15:24
When rmdir/unlink/rename removes an inode, the publish queue entry for
that inode was not cleaned up. If the deleted folder had been queued for
publishing, flush_publish_queue would later fail with "Folder inode N
not found" because the inode was already removed.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 55436d4d4c81
The FUSE publish pipeline (debounce + IPFS upload + IPNS publish) can
take slightly over 60s in CI. Double the polling attempts from 12 to 24
(keeping 5s intervals) to give sufficient headroom.

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

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
tests/desktop-e2e/scripts/test-round-trip.ps1 (1)

197-209: ⚠️ Potential issue | 🟡 Minor

Failure message says "24s" but actual polling duration is 48s.

Same inconsistency as the bash version. The loop runs 24 attempts × 2s sleep = 48s.

Proposed fix
-        Test-Fail "IPNS resolve did not return expected CID after 24s polling"
+        Test-Fail "IPNS resolve did not return expected CID after 48s polling"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/desktop-e2e/scripts/test-round-trip.ps1` around lines 197 - 209, The
failure message's duration is incorrect: the polling loop in the for construct
(for ($attempt = 1; $attempt -le 24 -and -not $ResolvedCid; $attempt++)) sleeps
2 seconds each iteration (Start-Sleep -Seconds 2) so total = 48s; update the
Test-Fail string "IPNS resolve did not return expected CID after 24s polling" to
reflect "48s" (and likewise adjust any related Test-Pass/diagnostic messages if
present) so the message matches the actual polling duration used by the loop and
variables $attempt, $ResolvedCid, $ApiUrl remain unchanged.
tests/desktop-e2e/scripts/test-round-trip.sh (2)

95-111: ⚠️ Potential issue | 🟡 Minor

Failure message still references old 60s timeout.

Line 111's failure message says "after 60s polling" but the loop now runs 24 iterations × 5s = 120s.

Proposed fix
-  fail "Vault has no rootIpnsName after 60s polling (error: $VAULT_ERROR)"
+  fail "Vault has no rootIpnsName after 120s polling (error: $VAULT_ERROR)"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/desktop-e2e/scripts/test-round-trip.sh` around lines 95 - 111, The
failure message still mentions "after 60s polling" but the loop now polls for 24
attempts × 5s = 120s; update the fail message to reflect the current timeout.
Locate the polling loop and the post-check that references ROOT_IPNS and
VAULT_RESPONSE (variables ROOT_IPNS, VAULT_RESPONSE and the for attempt in $(seq
1 24) loop) and change the static text "after 60s polling" to "after 120s
polling" (or compute/derive the timeout from attempt/count/delay if preferred)
so the error accurately reports the real timeout.

148-164: ⚠️ Potential issue | 🟡 Minor

Failure message says "24s" but actual polling duration is 48s.

The loop runs 24 attempts × 2s sleep = 48s total wait time.

Proposed fix
-    fail "IPNS resolve did not return expected CID after 24s polling (error: $IPNS_ERROR)"
+    fail "IPNS resolve did not return expected CID after 48s polling (error: $IPNS_ERROR)"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/desktop-e2e/scripts/test-round-trip.sh` around lines 148 - 164, The
failure message incorrectly states "24s" while the polling actually sleeps 2s
for 24 attempts (48s); update the fail message after the loop to reflect the
real timeout (48s) or compute it dynamically (e.g., attempts*sleep) so the
message matches the behavior—change the string in the fail call that currently
reads "IPNS resolve did not return expected CID after 24s polling (error:
$IPNS_ERROR)" to the correct duration and ensure this message is emitted in the
same block that references RESOLVED_CID and IPNS_RESPONSE.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@tests/desktop-e2e/scripts/test-round-trip.ps1`:
- Around line 197-209: The failure message's duration is incorrect: the polling
loop in the for construct (for ($attempt = 1; $attempt -le 24 -and -not
$ResolvedCid; $attempt++)) sleeps 2 seconds each iteration (Start-Sleep -Seconds
2) so total = 48s; update the Test-Fail string "IPNS resolve did not return
expected CID after 24s polling" to reflect "48s" (and likewise adjust any
related Test-Pass/diagnostic messages if present) so the message matches the
actual polling duration used by the loop and variables $attempt, $ResolvedCid,
$ApiUrl remain unchanged.

In `@tests/desktop-e2e/scripts/test-round-trip.sh`:
- Around line 95-111: The failure message still mentions "after 60s polling" but
the loop now polls for 24 attempts × 5s = 120s; update the fail message to
reflect the current timeout. Locate the polling loop and the post-check that
references ROOT_IPNS and VAULT_RESPONSE (variables ROOT_IPNS, VAULT_RESPONSE and
the for attempt in $(seq 1 24) loop) and change the static text "after 60s
polling" to "after 120s polling" (or compute/derive the timeout from
attempt/count/delay if preferred) so the error accurately reports the real
timeout.
- Around line 148-164: The failure message incorrectly states "24s" while the
polling actually sleeps 2s for 24 attempts (48s); update the fail message after
the loop to reflect the real timeout (48s) or compute it dynamically (e.g.,
attempts*sleep) so the message matches the behavior—change the string in the
fail call that currently reads "IPNS resolve did not return expected CID after
24s polling (error: $IPNS_ERROR)" to the correct duration and ensure this
message is emitted in the same block that references RESOLVED_CID and
IPNS_RESPONSE.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: a7be43c5-09a2-4f50-9bf2-a996c0d5dd8d

📥 Commits

Reviewing files that changed from the base of the PR and between 411d654 and b113877.

📒 Files selected for processing (2)
  • tests/desktop-e2e/scripts/test-round-trip.ps1
  • tests/desktop-e2e/scripts/test-round-trip.sh

…dir in E2E tests

The FUSE publish pipeline never fired in CI because after release()
spawns the background upload, no further FUSE callbacks triggered
drain_upload_completions(). The upload would complete and send its
result to the channel, but nothing drained it.

Two fixes:
1. Add drain_upload_completions() to handle_readdir() on macOS/Linux
   (Windows dir_ops already had it)
2. Add explicit `ls` / `Get-ChildItem` to E2E test scripts after file
   write to force a FUSE readdir callback, ensuring the upload drain
   fires even when no other filesystem activity occurs

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

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
tests/desktop-e2e/scripts/test-round-trip.ps1 (1)

202-214: ⚠️ Potential issue | 🟡 Minor

Minor: Error message arithmetic is off.

The loop runs 24 attempts with 2-second sleeps, totaling ~48 seconds of polling, but line 214 reports "24s polling".

Proposed fix
     if ($ResolvedCid) {
         Test-Pass "IPNS resolve returned CID ($ResolvedCid)"
     } else {
-        Test-Fail "IPNS resolve did not return expected CID after 24s polling"
+        Test-Fail "IPNS resolve did not return expected CID after 48s polling"
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/desktop-e2e/scripts/test-round-trip.ps1` around lines 202 - 214, The
failure message incorrectly states "24s polling" even though the for loop does
24 attempts with a 2-second Start-Sleep (≈48 seconds); update the Test-Fail call
so it reports the correct total polling duration (e.g., "48s polling") or
compute it dynamically from the loop variables ($attempt count * 2) before
calling Test-Fail; locate the loop using $attempt and $ResolvedCid and change
the string passed to Test-Fail (or replace it with a computed value) so the
reported duration matches the actual polling time.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@tests/desktop-e2e/scripts/test-round-trip.ps1`:
- Around line 202-214: The failure message incorrectly states "24s polling" even
though the for loop does 24 attempts with a 2-second Start-Sleep (≈48 seconds);
update the Test-Fail call so it reports the correct total polling duration
(e.g., "48s polling") or compute it dynamically from the loop variables
($attempt count * 2) before calling Test-Fail; locate the loop using $attempt
and $ResolvedCid and change the string passed to Test-Fail (or replace it with a
computed value) so the reported duration matches the actual polling time.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: ba1aad48-5b3e-468b-a7bd-0a33e1a30b0f

📥 Commits

Reviewing files that changed from the base of the PR and between b113877 and 5670444.

📒 Files selected for processing (3)
  • crates/fuse/src/dir_ops.rs
  • tests/desktop-e2e/scripts/test-round-trip.ps1
  • tests/desktop-e2e/scripts/test-round-trip.sh
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/desktop-e2e/scripts/test-round-trip.sh

FSM1 and others added 2 commits April 5, 2026 22:01
The single ls after file write wasn't sufficient on macOS — FUSE-T's
SMB backend caches directory listings. Add stat + ls on each polling
iteration to repeatedly trigger lookup/getattr/readdir callbacks,
ensuring drain_upload_completions() fires even with SMB caching.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 79529e555970
Windows E2E was passing before the polling changes. Revert to the
original test-round-trip.ps1 from main — the FUSE drain fixes are
only needed for macOS FUSE-T's SMB backend.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 8450bb21af72
@FSM1 FSM1 force-pushed the fix/desktop-e2e-sequence-mismatch branch from 8ea1325 to 71515f2 Compare April 6, 2026 08:40
- Log warnings on IPNS sequence parse failures instead of silent unwrap_or(0)
- Add CID mismatch warning and use DB columns as authoritative in parseCachedRecord
- Add bounds checks and fail-closed behavior in protobuf group wire type scanning
- Redirect API stdout/stderr to log file in desktop E2E workflow for artifact collection
- Add test for sequence/CID mismatch between signed record bytes and DB columns

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

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

Comment thread apps/web/src/services/ipns.service.ts
Comment thread apps/api/src/ipns/ipns-record-parser.ts
Comment thread tests/desktop-e2e/scripts/test-round-trip.sh
Comment thread tests/desktop-e2e/scripts/test-round-trip.sh
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 0d2b6601683b
@FSM1 FSM1 merged commit 18b4e26 into main Apr 6, 2026
33 checks passed
@FSM1 FSM1 deleted the fix/desktop-e2e-sequence-mismatch branch April 14, 2026 00:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

release:api:fix Patch version bump (bug fix) for api release:cipherbox-fuse:fix Patch version bump (bug fix) for cipherbox-fuse release:cipherbox-sdk:fix Patch version bump (bug fix) for cipherbox-sdk release:desktop:fix Patch version bump (bug fix) for desktop release:sdk:fix Patch version bump (bug fix) for sdk release:sdk-core:fix Patch version bump (bug fix) for sdk-core release:tee-worker:fix Patch version bump (bug fix) for tee-worker release:web:fix Patch version bump (bug fix) for web

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants