Skip to content

fix: ci issues#288

Merged
ScriptedBro merged 3 commits into
mainfrom
fix/ci-issues
Jul 11, 2026
Merged

fix: ci issues#288
ScriptedBro merged 3 commits into
mainfrom
fix/ci-issues

Conversation

@ScriptedBro

@ScriptedBro ScriptedBro commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Summary

Type of change

  • [ X] Bug fix
  • New feature
  • Breaking change
  • Documentation

Test plan

  • [ X] pnpm typecheck
  • [ X] pnpm test
  • [X ] Manual testing (describe):

Checklist

  • Follows project code conventions
  • TODOs reference issues where applicable
  • No secrets or credentials committed

Summary by CodeRabbit

  • New Features

    • Added a new authentication audit action for refresh.
    • Escrow release now requires and validates an explicit recipient, and partial settlement now updates released amounts/status accordingly.
  • Bug Fixes

    • Improved email retry behavior in tests, refined retry timer execution, and corrected queue/worker behavior during testing.
    • Enhanced wallet sequence reservation lock reliability with retry-based acquisition.
    • Updated escrow and permission test expectations plus logout/session cookie invalidation behavior for consistency.

@coderabbitai

coderabbitai Bot commented Jul 8, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 2e93015b-728f-4963-8884-43f466d470f7

📥 Commits

Reviewing files that changed from the base of the PR and between 01f3c51 and a948d1e.

📒 Files selected for processing (3)
  • .github/workflows/ci.yml
  • tests/integration/package.json
  • tests/unit/package.json
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/unit/package.json

📝 Walkthrough

Walkthrough

This PR updates escrow release and deposit call shapes, refreshes related escrow and permission snapshots, and adjusts backend test and runtime setup for notifications, orchestrator, wallet, payments, gateway, CI, and test runners.

Changes

Escrow Contract Release and Snapshot Updates

Layer / File(s) Summary
Release and partial release behavior
contracts/escrow/src/lib.rs
release now accepts and validates a recipient address, and partial_release now transfers to the seller while tracking released_amount and persisting the updated escrow state.
Rust escrow test updates
contracts/escrow/src/integration_tests.rs, contracts/escrow/src/test.rs, contracts/tests/cross_contract.rs
integration_tests.rs, test.rs, and cross_contract.rs now pass the expanded deposit arguments and the new release recipient/seller arguments, and metadata tests use registered Stellar asset tokens.
Deposit snapshot argument updates
contracts/escrow/test_snapshots/integration_tests/*, contracts/tests/test_snapshots/*
Many escrow snapshots now record two trailing void arguments on deposit calls to match the updated contract signature.
Release and escrow-state snapshots
contracts/escrow/test_snapshots/integration_tests/test_full_release_via_release_still_works.1.json, test_release_with_wrong_recipient_fails.1.json, test_release_wrong_caller.1.json, test_release_on_refunded_escrow_fails.1.json, test_refund_on_released_escrow_fails.1.json
Escrow snapshots now reflect the recipient-bearing release call, new released_amount storage, and added refunded/released escrow failure fixtures.
New escrow scenario snapshots
contracts/escrow/test_snapshots/integration_tests/*, contracts/escrow/test_snapshots/test/test/*, contracts/tests/test_snapshots/*
New full snapshot fixtures cover admin transfer, co-admin, dispute, purchase lifecycle, refund lifecycle, metadata, and escrow event scenarios.

Permissions Contract Event Snapshot Updates

Layer / File(s) Summary
Permission event fixtures
contracts/permissions/test_snapshots/test/test/*
New and updated permission snapshots record allowance-increased and merchant-list event payloads, including cases with empty event lists.

Backend Test and Infrastructure Fixes

Layer / File(s) Summary
Auth and gateway test changes
apps/backend/gateway/src/auth/authAuditEvent.ts, tests/unit/src/gateway-auth-handlers.test.js
AUTH_AUDIT_ACTIONS gains REFRESH, and the gateway logout test now uses a generated token and a revised cookie expiration assertion.
Notifications email and Redis test setup
apps/backend/notifications/email/{config,dlq,dlq.test,index.test}.ts, apps/backend/notifications/src/integration.test.ts
Email retry/DLQ tests, DLQ imports, SendGrid mocks, and Redis integration test setup are adjusted for the current module paths and fake-timer behavior, and retry config reloads in test mode.
Orchestrator test-mode gating and Redis mock support
apps/backend/orchestrator/package.json, apps/backend/orchestrator/src/index.ts, apps/backend/orchestrator/workflows/checkout/index.ts
ioredis-mock is added, checkout timeout queue/worker setup is skipped in test mode, and timeout scheduling/cancelation short-circuit during tests.
Payments typing and wallet lock retry
apps/backend/payments/src/validation.ts, apps/backend/wallet/src/queue/txQueue.ts
Refund reason validation now uses the on-chain type, and wallet sequence reservation retries Redis lock acquisition before failing.
Test runner and environment config updates
tests/unit/package.json, tests/unit/src/queue-job-status.test.js, tests/unit/src/rateLimit.test.js, .github/workflows/ci.yml, tests/integration/package.json
The unit test runner command changes to --import tsx, tests preserve and restore NODE_ENV, rate-limit tests enable mocked Redis, CI sets test environment variables, and integration scripts export the same values.

Estimated code review effort: 4 (Complex) | ~75 minutes

Possibly related PRs

  • DelegoLabs/Delego#41: Both PRs touch the escrow release flow in contracts/escrow/src/lib.rs.
  • DelegoLabs/Delego#81: Both PRs affect escrow release and seller payout logic in contracts/escrow/src/lib.rs.
  • DelegoLabs/Delego#169: Both PRs touch apps/backend/payments/src/validation.ts for refund reason code handling.

Poem

A rabbit hops through escrow's maze,
Recipient checks and seller pays.
Void args line up, snapshots gleam,
Mercer-list events now change their theme.
I twitch my nose at retry loops tight,
And bound the lock with test-mode light 🐇

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The title is related to the PR, but it is too vague to indicate the specific CI and test-environment changes. Rename it to something specific like "fix CI test environment variables for Redis and Node".
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/ci-issues

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.

@ScriptedBro ScriptedBro changed the title Fix/ci issues Fix: ci issues Jul 8, 2026
@ScriptedBro ScriptedBro changed the title Fix: ci issues fix: ci issues Jul 8, 2026

@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: 3

🧹 Nitpick comments (3)
tests/unit/src/rateLimit.test.js (1)

7-7: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider saving/restoring MOCK_REDIS for consistency with the queue-job-status test pattern.

The before hook sets MOCK_REDIS but the after hook never cleans it up, unlike the careful save/restore pattern applied to NODE_ENV in queue-job-status.test.js in this same PR. While node --test isolates files into separate processes, applying the same cleanup pattern here would keep the test infrastructure fixes consistent and future-proof.

♻️ Suggested cleanup for consistency
 describe("Gateway Rate Limiting System", () => {
+  let originalMockRedis;
   before(async () => {
+    originalMockRedis = process.env.MOCK_REDIS;
     process.env.MOCK_REDIS = "true";
     // Ensure mock Redis connection is initialized safely from compiled code
     getRedisClient();
   });
 
   after(async () => {
+    if (originalMockRedis === undefined) {
+      delete process.env.MOCK_REDIS;
+    } else {
+      process.env.MOCK_REDIS = originalMockRedis;
+    }
     // Gracefully clean up our Redis connections
     await disconnectRedis();
   });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/unit/src/rateLimit.test.js` at line 7, The test setup in
rateLimit.test.js sets MOCK_REDIS in the `before` hook but never restores it,
unlike the save/restore pattern used in the `queue-job-status` test. Update the
test lifecycle around the existing `before`/`after` hooks in `rateLimit.test.js`
to preserve any prior `MOCK_REDIS` value and restore or delete it afterward,
using the same cleanup approach as the `queue-job-status.test.js` pattern for
consistency and future-proofing.
tests/unit/src/gateway-auth-handlers.test.js (1)

11-11: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Import generateToken from the source file instead of dist/. apps/backend/gateway/dist/src/auth/authService.js isn’t tracked, so this test depends on a prior build; apps/backend/gateway/src/auth/authService.ts already exports generateToken.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/unit/src/gateway-auth-handlers.test.js` at line 11, The test is
importing generateToken from the built dist artifact, which makes it depend on a
prior build. Update the import in gateway-auth-handlers.test.js to reference the
source authService module instead of dist, using the generateToken export from
apps/backend/gateway/src/auth/authService.ts so the test runs directly from
source.
contracts/escrow/src/test.rs (1)

192-195: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Extract duplicated token setup into a helper.

The same 5-line token setup block (register Stellar asset, create client, mint, add_token) is repeated in test_deposit_with_metadata_success, test_deposit_without_metadata, and test_deposit_with_partial_metadata. Extracting a helper would reduce duplication and ensure consistent setup.

♻️ Suggested helper extraction
fn setup_token(
    env: &Env,
    buyer: &Address,
    admin: &Address,
    client: &EscrowContractClient,
) -> Address {
    let token_admin = Address::generate(env);
    let token = env.register_stellar_asset_contract_v2(token_admin).address();
    let token_admin_client = soroban_sdk::token::StellarAssetClient::new(env, &token);
    token_admin_client.mint(buyer, &10000i128);
    client.add_token(admin, &token);
    token
}

Then each test replaces the 5-line block with:

let token = setup_token(&env, &buyer, &admin, &client);

Also applies to: 227-230, 260-263

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@contracts/escrow/src/test.rs` around lines 192 - 195, The token setup logic
is duplicated across the escrow tests, so extract it into a shared helper to
keep the setup consistent and reduce repetition. Move the repeated
register/mint/add_token sequence into a helper like setup_token in test.rs,
using the same symbols Env, Address, StellarAssetClient, and
EscrowContractClient, then replace each repeated block in
test_deposit_with_metadata_success, test_deposit_without_metadata, and
test_deposit_with_partial_metadata with a single helper call.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/backend/wallet/src/queue/txQueue.ts`:
- Around line 199-215: The lock retry loop in txQueue’s sequence reservation is
too short relative to the lock holder’s `lockTimeout`, and its fixed
`retryDelay` causes synchronized retries. Update the retry logic around the
`redis.set` lock acquisition so the total wait budget matches the expected lock
hold time (or derives from `lockTimeout`), add jitter/backoff to the delay, and
avoid sleeping after the last failed attempt. Use the existing lock-acquire
block in `txQueue` as the place to tune the `maxRetries`, `retryDelay`, and
failure path.

In `@contracts/escrow/test_snapshots/integration_tests/test_escrow_events.1.json`:
- Around line 707-974: The escrow snapshot is stale against the current
EscrowRecord schema: these contract_data entries still serialize unlock_time and
status-only payloads, but the persisted shape now includes timeout_ledger,
released_amount, created_at, escrow_id, and order_id. Regenerate the affected
snapshot data in test_escrow_events.1.json using the current escrow event/test
output so the EscrowRecord fixtures match the updated schema and symbols like
contract_data, Escrow, status, and unlock_time are refreshed consistently.

In
`@contracts/escrow/test_snapshots/integration_tests/test_remove_co_admin.1.json`:
- Around line 459-517: The EscrowRecord snapshot in this test fixture is missing
the new persisted released_amount field, so update the test snapshot data to
include released_amount: 0 alongside the existing EscrowRecord keys. Use the
EscrowRecord snapshot structure in test_remove_co_admin.1.json as the target and
keep it consistent with the other escrow snapshots that already include
released_amount.

---

Nitpick comments:
In `@contracts/escrow/src/test.rs`:
- Around line 192-195: The token setup logic is duplicated across the escrow
tests, so extract it into a shared helper to keep the setup consistent and
reduce repetition. Move the repeated register/mint/add_token sequence into a
helper like setup_token in test.rs, using the same symbols Env, Address,
StellarAssetClient, and EscrowContractClient, then replace each repeated block
in test_deposit_with_metadata_success, test_deposit_without_metadata, and
test_deposit_with_partial_metadata with a single helper call.

In `@tests/unit/src/gateway-auth-handlers.test.js`:
- Line 11: The test is importing generateToken from the built dist artifact,
which makes it depend on a prior build. Update the import in
gateway-auth-handlers.test.js to reference the source authService module instead
of dist, using the generateToken export from
apps/backend/gateway/src/auth/authService.ts so the test runs directly from
source.

In `@tests/unit/src/rateLimit.test.js`:
- Line 7: The test setup in rateLimit.test.js sets MOCK_REDIS in the `before`
hook but never restores it, unlike the save/restore pattern used in the
`queue-job-status` test. Update the test lifecycle around the existing
`before`/`after` hooks in `rateLimit.test.js` to preserve any prior `MOCK_REDIS`
value and restore or delete it afterward, using the same cleanup approach as the
`queue-job-status.test.js` pattern for consistency and future-proofing.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 56290e4b-2e21-4624-bb5b-908add3c8234

📥 Commits

Reviewing files that changed from the base of the PR and between a86091a and 01f3c51.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (84)
  • apps/backend/gateway/src/auth/authAuditEvent.ts
  • apps/backend/notifications/email/config.test.ts
  • apps/backend/notifications/email/config.ts
  • apps/backend/notifications/email/dlq.test.ts
  • apps/backend/notifications/email/dlq.ts
  • apps/backend/notifications/email/errorClassifier.ts
  • apps/backend/notifications/email/index.test.ts
  • apps/backend/notifications/email/types.ts
  • apps/backend/notifications/src/integration.test.ts
  • apps/backend/orchestrator/package.json
  • apps/backend/orchestrator/src/index.ts
  • apps/backend/orchestrator/workflows/checkout/index.ts
  • apps/backend/payments/src/validation.ts
  • apps/backend/wallet/src/queue/txQueue.ts
  • contracts/escrow/src/integration_tests.rs
  • contracts/escrow/src/lib.rs
  • contracts/escrow/src/test.rs
  • contracts/escrow/test_snapshots/integration_tests/test_accept_admin_wrong_address.1.json
  • contracts/escrow/test_snapshots/integration_tests/test_cancel_admin_transfer.1.json
  • contracts/escrow/test_snapshots/integration_tests/test_co_admin_accepts_primary_admin.1.json
  • contracts/escrow/test_snapshots/integration_tests/test_co_admin_dispute_resolution.1.json
  • contracts/escrow/test_snapshots/integration_tests/test_co_admin_restrictions.1.json
  • contracts/escrow/test_snapshots/integration_tests/test_deposit_with_whitelisted_token_succeeds.1.json
  • contracts/escrow/test_snapshots/integration_tests/test_dispute_blocks_release_and_refund.1.json
  • contracts/escrow/test_snapshots/integration_tests/test_dispute_resolution_to_buyer.1.json
  • contracts/escrow/test_snapshots/integration_tests/test_dispute_resolution_to_seller.1.json
  • contracts/escrow/test_snapshots/integration_tests/test_double_refund_prevention.1.json
  • contracts/escrow/test_snapshots/integration_tests/test_double_release_prevention.1.json
  • contracts/escrow/test_snapshots/integration_tests/test_escrow_events.1.json
  • contracts/escrow/test_snapshots/integration_tests/test_full_purchase_lifecycle.1.json
  • contracts/escrow/test_snapshots/integration_tests/test_full_refund_lifecycle.1.json
  • contracts/escrow/test_snapshots/integration_tests/test_full_release_via_release_still_works.1.json
  • contracts/escrow/test_snapshots/integration_tests/test_get_escrow_returns_full_record.1.json
  • contracts/escrow/test_snapshots/integration_tests/test_get_receipt_disputed_state.1.json
  • contracts/escrow/test_snapshots/integration_tests/test_get_receipt_funded_state.1.json
  • contracts/escrow/test_snapshots/integration_tests/test_get_receipt_refunded_state.1.json
  • contracts/escrow/test_snapshots/integration_tests/test_get_receipt_released_state.1.json
  • contracts/escrow/test_snapshots/integration_tests/test_old_admin_loses_privileges.1.json
  • contracts/escrow/test_snapshots/integration_tests/test_partial_release_50_percent_stays_active.1.json
  • contracts/escrow/test_snapshots/integration_tests/test_partial_release_exceeds_remaining_balance.1.json
  • contracts/escrow/test_snapshots/integration_tests/test_partial_release_remaining_50_percent_released.1.json
  • contracts/escrow/test_snapshots/integration_tests/test_partial_release_zero_amount.1.json
  • contracts/escrow/test_snapshots/integration_tests/test_refund_after_partial_release_refunds_unreleased_only.1.json
  • contracts/escrow/test_snapshots/integration_tests/test_refund_before_timeout_fails.1.json
  • contracts/escrow/test_snapshots/integration_tests/test_refund_eligibility_admin_always_eligible.1.json
  • contracts/escrow/test_snapshots/integration_tests/test_refund_eligibility_already_refunded.1.json
  • contracts/escrow/test_snapshots/integration_tests/test_refund_eligibility_already_released.1.json
  • contracts/escrow/test_snapshots/integration_tests/test_refund_eligibility_buyer_after_timeout.1.json
  • contracts/escrow/test_snapshots/integration_tests/test_refund_eligibility_buyer_before_timeout.1.json
  • contracts/escrow/test_snapshots/integration_tests/test_refund_eligibility_disputed.1.json
  • contracts/escrow/test_snapshots/integration_tests/test_refund_eligibility_seller_always_eligible.1.json
  • contracts/escrow/test_snapshots/integration_tests/test_refund_eligibility_unauthorized_stranger.1.json
  • contracts/escrow/test_snapshots/integration_tests/test_refund_on_released_escrow_fails.1.json
  • contracts/escrow/test_snapshots/integration_tests/test_release_eligibility_disputed_blocks_release.1.json
  • contracts/escrow/test_snapshots/integration_tests/test_release_eligibility_funded_before_timeout.1.json
  • contracts/escrow/test_snapshots/integration_tests/test_release_eligibility_terminal_refund_blocks_release.1.json
  • contracts/escrow/test_snapshots/integration_tests/test_release_eligibility_terminal_release_blocks_release.1.json
  • contracts/escrow/test_snapshots/integration_tests/test_release_eligibility_timeout_blocks_release.1.json
  • contracts/escrow/test_snapshots/integration_tests/test_release_on_refunded_escrow_fails.1.json
  • contracts/escrow/test_snapshots/integration_tests/test_release_with_wrong_recipient_fails.1.json
  • contracts/escrow/test_snapshots/integration_tests/test_release_wrong_caller.1.json
  • contracts/escrow/test_snapshots/integration_tests/test_remove_co_admin.1.json
  • contracts/escrow/test_snapshots/integration_tests/test_timeout_auto_refund.1.json
  • contracts/escrow/test_snapshots/integration_tests/test_two_step_admin_transfer.1.json
  • contracts/escrow/test_snapshots/test/test/test_deposit_with_metadata_success.1.json
  • contracts/escrow/test_snapshots/test/test/test_deposit_with_partial_metadata.1.json
  • contracts/escrow/test_snapshots/test/test/test_deposit_without_metadata.1.json
  • contracts/escrow/test_snapshots/test/test/test_get_escrow_metadata_not_found.1.json
  • contracts/permissions/test_snapshots/test/test/test_allowance_increased_event_emitted.1.json
  • contracts/permissions/test_snapshots/test/test/test_allowance_increased_event_not_emitted_on_decrease.1.json
  • contracts/permissions/test_snapshots/test/test/test_allowance_increased_event_not_emitted_on_unchanged_limit.1.json
  • contracts/permissions/test_snapshots/test/test/test_allowance_increased_not_found.1.json
  • contracts/permissions/test_snapshots/test/test/test_merchant_list_event.1.json
  • contracts/permissions/test_snapshots/test/test/test_merchant_list_event_not_emitted.1.json
  • contracts/permissions/test_snapshots/test/test/test_non_self_delegation_succeeds.1.json
  • contracts/permissions/test_snapshots/test/test/test_self_delegation_allowed_when_config_enabled.1.json
  • contracts/permissions/test_snapshots/test/test/test_unpause_grants_allows_new_grants.1.json
  • contracts/tests/cross_contract.rs
  • contracts/tests/test_snapshots/test_end_to_end_delegated_purchase.1.json
  • contracts/tests/test_snapshots/test_permission_checked_before_escrow_fund_succeeds.1.json
  • tests/unit/package.json
  • tests/unit/src/gateway-auth-handlers.test.js
  • tests/unit/src/queue-job-status.test.js
  • tests/unit/src/rateLimit.test.js
💤 Files with no reviewable changes (1)
  • apps/backend/orchestrator/src/index.ts

Comment on lines +199 to 215
// Acquire lock with retry
let lockAcquired = false;
const maxRetries = 20;
const retryDelay = 50; // 50ms

for (let attempt = 0; attempt < maxRetries; attempt++) {
const res = await redis.set(lockKey, "locked", "PX", lockTimeout, "NX");
if (res) {
lockAcquired = true;
break;
}
await new Promise((resolve) => setTimeout(resolve, retryDelay));
}

if (!lockAcquired) {
throw new Error("Failed to acquire sequence reservation lock");
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Retry budget (~1s) is much smaller than lockTimeout (5s), and fixed delay causes synchronized retries.

The total wait before giving up is maxRetries * retryDelay20 * 50ms = 1000ms, but the lock holder can legitimately hold the lock for up to lockTimeout (5000ms) — the critical section performs horizonServer.loadAccount(address) (a network call) while holding it. Under normal contention a waiter can exhaust its ~1s budget and throw "Failed to acquire sequence reservation lock" even though the holder is progressing normally, which will surface as spurious reservation failures.

Two issues:

  1. The retry budget should be aligned with the realistic worst-case hold time (≈ lockTimeout), not ~1/5 of it.
  2. The fixed retryDelay with no jitter causes concurrent waiters to retry in lockstep (thundering herd). Adding jitter/backoff spreads contention. The loop also sleeps once more after the final failed attempt.
♻️ Suggested retry tuning with jitter and no trailing sleep
   // Acquire lock with retry
   let lockAcquired = false;
-  const maxRetries = 20;
-  const retryDelay = 50; // 50ms
+  const maxRetries = 100;
+  const retryDelay = 50; // base 50ms; total budget ~lockTimeout
 
   for (let attempt = 0; attempt < maxRetries; attempt++) {
     const res = await redis.set(lockKey, "locked", "PX", lockTimeout, "NX");
     if (res) {
       lockAcquired = true;
       break;
     }
-    await new Promise((resolve) => setTimeout(resolve, retryDelay));
+    // Skip sleeping after the last attempt; add jitter to avoid lockstep retries.
+    if (attempt < maxRetries - 1) {
+      const jitter = Math.floor(Math.random() * retryDelay);
+      await new Promise((resolve) => setTimeout(resolve, retryDelay + jitter));
+    }
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Acquire lock with retry
let lockAcquired = false;
const maxRetries = 20;
const retryDelay = 50; // 50ms
for (let attempt = 0; attempt < maxRetries; attempt++) {
const res = await redis.set(lockKey, "locked", "PX", lockTimeout, "NX");
if (res) {
lockAcquired = true;
break;
}
await new Promise((resolve) => setTimeout(resolve, retryDelay));
}
if (!lockAcquired) {
throw new Error("Failed to acquire sequence reservation lock");
}
// Acquire lock with retry
let lockAcquired = false;
const maxRetries = 100;
const retryDelay = 50; // base 50ms; total budget ~lockTimeout
for (let attempt = 0; attempt < maxRetries; attempt++) {
const res = await redis.set(lockKey, "locked", "PX", lockTimeout, "NX");
if (res) {
lockAcquired = true;
break;
}
// Skip sleeping after the last attempt; add jitter to avoid lockstep retries.
if (attempt < maxRetries - 1) {
const jitter = Math.floor(Math.random() * retryDelay);
await new Promise((resolve) => setTimeout(resolve, retryDelay + jitter));
}
}
if (!lockAcquired) {
throw new Error("Failed to acquire sequence reservation lock");
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/backend/wallet/src/queue/txQueue.ts` around lines 199 - 215, The lock
retry loop in txQueue’s sequence reservation is too short relative to the lock
holder’s `lockTimeout`, and its fixed `retryDelay` causes synchronized retries.
Update the retry logic around the `redis.set` lock acquisition so the total wait
budget matches the expected lock hold time (or derives from `lockTimeout`), add
jitter/backoff to the delay, and avoid sleeping after the last failed attempt.
Use the existing lock-acquire block in `txQueue` as the place to tune the
`maxRetries`, `retryDelay`, and failure path.

Comment on lines +707 to +974
"val": {
"map": [
{
"key": {
"symbol": "amount"
},
"val": {
"i128": {
"hi": 0,
"lo": 1000
}
}
},
{
"key": {
"symbol": "buyer"
},
"val": {
"address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4"
}
},
{
"key": {
"symbol": "seller"
},
"val": {
"address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M"
}
},
{
"key": {
"symbol": "status"
},
"val": {
"vec": [
{
"symbol": "Released"
}
]
}
},
{
"key": {
"symbol": "token"
},
"val": {
"address": "CACMVW2KK4H5FZDFF2AUCAKQTEJMZZWJUIZF23XMRVYQBSXYLHZ6BKWN"
}
},
{
"key": {
"symbol": "unlock_time"
},
"val": {
"u64": 3600
}
}
]
}
}
},
"ext": "v0"
},
4095
]
],
[
{
"contract_data": {
"contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOLZM",
"key": {
"vec": [
{
"symbol": "Escrow"
},
{
"u64": 2
}
]
},
"durability": "persistent"
}
},
[
{
"last_modified_ledger_seq": 0,
"data": {
"contract_data": {
"ext": "v0",
"contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOLZM",
"key": {
"vec": [
{
"symbol": "Escrow"
},
{
"u64": 2
}
]
},
"durability": "persistent",
"val": {
"map": [
{
"key": {
"symbol": "amount"
},
"val": {
"i128": {
"hi": 0,
"lo": 1000
}
}
},
{
"key": {
"symbol": "buyer"
},
"val": {
"address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4"
}
},
{
"key": {
"symbol": "seller"
},
"val": {
"address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M"
}
},
{
"key": {
"symbol": "status"
},
"val": {
"vec": [
{
"symbol": "Refunded"
}
]
}
},
{
"key": {
"symbol": "token"
},
"val": {
"address": "CACMVW2KK4H5FZDFF2AUCAKQTEJMZZWJUIZF23XMRVYQBSXYLHZ6BKWN"
}
},
{
"key": {
"symbol": "unlock_time"
},
"val": {
"u64": 3600
}
}
]
}
}
},
"ext": "v0"
},
4095
]
],
[
{
"contract_data": {
"contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOLZM",
"key": {
"vec": [
{
"symbol": "Escrow"
},
{
"u64": 3
}
]
},
"durability": "persistent"
}
},
[
{
"last_modified_ledger_seq": 0,
"data": {
"contract_data": {
"ext": "v0",
"contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOLZM",
"key": {
"vec": [
{
"symbol": "Escrow"
},
{
"u64": 3
}
]
},
"durability": "persistent",
"val": {
"map": [
{
"key": {
"symbol": "amount"
},
"val": {
"i128": {
"hi": 0,
"lo": 1000
}
}
},
{
"key": {
"symbol": "buyer"
},
"val": {
"address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4"
}
},
{
"key": {
"symbol": "seller"
},
"val": {
"address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M"
}
},
{
"key": {
"symbol": "status"
},
"val": {
"vec": [
{
"symbol": "Released"
}
]
}
},
{
"key": {
"symbol": "token"
},
"val": {
"address": "CACMVW2KK4H5FZDFF2AUCAKQTEJMZZWJUIZF23XMRVYQBSXYLHZ6BKWN"
}
},
{
"key": {
"symbol": "unlock_time"
},
"val": {
"u64": 3600
}
}
]
}
}
},
"ext": "v0"
},
4095
]
],

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
ast-grep run --pattern 'struct EscrowRecord {
  $$$
}' --lang rust contracts/escrow/src/lib.rs
rg -n "released_amount|created_at|order_id" contracts/escrow/src/lib.rs

Repository: DelegoLabs/Delego

Length of output: 1020


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Show the current EscrowRecord definition and nearby persistence/event code.
sed -n '1,120p' contracts/escrow/src/lib.rs
printf '\n---\n'
sed -n '730,770p' contracts/escrow/src/lib.rs
printf '\n---\n'
sed -n '820,845p' contracts/escrow/src/lib.rs
printf '\n---\n'
sed -n '1048,1105p' contracts/escrow/src/lib.rs

printf '\n=== snapshot field checks ===\n'
# Compare against other snapshot fixtures that include the newer schema fields.
rg -n '"released_amount"|"created_at"|"order_id"|"escrow_id"' contracts/escrow/test_snapshots/integration_tests/test_double_refund_prevention.1.json
printf '\n---\n'
rg -n '"released_amount"|"created_at"|"order_id"|"escrow_id"' contracts/escrow/test_snapshots/integration_tests/test_escrow_events.1.json

Repository: DelegoLabs/Delego

Length of output: 7205


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Check whether the contract still uses the old `unlock_time` field name anywhere.
rg -n "unlock_time|timeout_ledger" contracts/escrow/src/lib.rs contracts/escrow/test_snapshots/integration_tests/test_escrow_events.1.json

Repository: DelegoLabs/Delego

Length of output: 1281


Regenerate this escrow snapshot for the current schema. These records still use unlock_time and omit released_amount, created_at, escrow_id, and order_id, while EscrowRecord now persists timeout_ledger plus those fields. The fixture is stale and will diverge from the test output.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@contracts/escrow/test_snapshots/integration_tests/test_escrow_events.1.json`
around lines 707 - 974, The escrow snapshot is stale against the current
EscrowRecord schema: these contract_data entries still serialize unlock_time and
status-only payloads, but the persisted shape now includes timeout_ledger,
released_amount, created_at, escrow_id, and order_id. Regenerate the affected
snapshot data in test_escrow_events.1.json using the current escrow event/test
output so the EscrowRecord fixtures match the updated schema and symbols like
contract_data, Escrow, status, and unlock_time are refreshed consistently.

Comment on lines +459 to +517
"val": {
"map": [
{
"key": {
"symbol": "amount"
},
"val": {
"i128": {
"hi": 0,
"lo": 1000
}
}
},
{
"key": {
"symbol": "buyer"
},
"val": {
"address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4"
}
},
{
"key": {
"symbol": "seller"
},
"val": {
"address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M"
}
},
{
"key": {
"symbol": "status"
},
"val": {
"vec": [
{
"symbol": "Disputed"
}
]
}
},
{
"key": {
"symbol": "token"
},
"val": {
"address": "CACMVW2KK4H5FZDFF2AUCAKQTEJMZZWJUIZF23XMRVYQBSXYLHZ6BKWN"
}
},
{
"key": {
"symbol": "unlock_time"
},
"val": {
"u64": 3600
}
}
]
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
ast-grep run --pattern 'struct EscrowRecord {
  $$$
}' --lang rust contracts/escrow/src/lib.rs

Repository: DelegoLabs/Delego

Length of output: 155


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n## repo files matching escrow/lib and snapshots ##\n'
git ls-files | rg 'contracts/.*/(lib\.rs|test_snapshots/.*\.json)$|EscrowRecord|released_amount' || true

printf '\n## search for EscrowRecord references ##\n'
rg -n "EscrowRecord|released_amount" contracts/escrow -S || true

printf '\n## list snapshot fixtures mentioning released_amount ##\n'
rg -n '"released_amount"' contracts/escrow/test_snapshots -S || true

Repository: DelegoLabs/Delego

Length of output: 29119


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n## target snapshot section ##\n'
sed -n '430,540p' contracts/escrow/test_snapshots/integration_tests/test_remove_co_admin.1.json

printf '\n## reference snapshot section with released_amount ##\n'
sed -n '430,540p' contracts/escrow/test_snapshots/integration_tests/test_double_refund_prevention.1.json

Repository: DelegoLabs/Delego

Length of output: 7169


Add released_amount: 0 to this snapshot. EscrowRecord now persists released_amount, and this fixture omits that field while the other escrow snapshots include it.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@contracts/escrow/test_snapshots/integration_tests/test_remove_co_admin.1.json`
around lines 459 - 517, The EscrowRecord snapshot in this test fixture is
missing the new persisted released_amount field, so update the test snapshot
data to include released_amount: 0 alongside the existing EscrowRecord keys. Use
the EscrowRecord snapshot structure in test_remove_co_admin.1.json as the target
and keep it consistent with the other escrow snapshots that already include
released_amount.

@ScriptedBro
ScriptedBro merged commit 5aff918 into main Jul 11, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant