Conversation
The tenant-boundaries refactor rewrote idempotency.ts and dropped the fingerprint helper that transferOrchestrator.ts imports, leaving retries without a stable fingerprint. Restore buildIdempotencyFingerprint, getIdempotencyHashThreshold and the stable stringifier, and add regression tests for export and fingerprint stability.
|
@solaawojobi00-bit Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
CI status: failures come from
|
| Failing jobs | Root cause (from job logs) |
|---|---|
| Backend build, Backend lint + test, backend-governance, Backend Test Coverage | backend/prisma/schema.prisma:677: model WalletTenantAssociation has no closing } before model IdempotencyKey (Prisma P1012). Prisma generate fails, so every suite errors with @prisma/client did not initialize yet. |
| Verify CODEOWNERS, PR Template & Contribution Rules | ERR_PNPM_LOCKFILE_CONFIG_MISMATCH: the overrides in package.json don't match the lockfile. |
| CodeQL (TypeScript), Frontend Test Coverage | npm ci fails with EUSAGE: the frontend package-lock.json is out of sync (@tanstack/query-sync-storage-persister, @tanstack/react-query-persist-client, framer-motion missing). |
| CodeQL (Rust), Cargo Security Audit, NPM/PNPM audits, Dependency Vulnerability Scan, GitHub Dependency Review | Existing toolchain and dependency-audit failures across the repo. |
#1491 fails the same set of 13 jobs. These failures are deterministic, not flakes, so re-running won't clear them.
Verified locally for this change:
PASS src/__tests__/idempotencyFingerprint.test.ts
Tests: 9 passed, 9 total
With the idempotency.ts change reverted, the same suite gives 9 failed, 9 total.
…potency-fingerprint # Conflicts: # backend/src/idempotency.ts
fix(#1376): restore exported
buildIdempotencyFingerprinthelperProblem
backend/src/transferOrchestrator.tsfingerprints every canonicalised transfer withbuildIdempotencyFingerprintfrom./idempotency, then hands that fingerprint to the idempotency store. Commit 5db5f6e (the tenant-boundaries refactor) replacedbackend/src/idempotency.tswholesale and dropped the helper along with itsgetIdempotencyHashThresholdandstableStringifycompanions. Nothing else was removed from the import list's point of view, so the missing export is easy to miss:ts-jestruns withdiagnostics: false, so the unresolved import doesn't fail test compilation.undefined, sobuildIdempotencyFingerprint(canonical)throws on the first transfer.import { buildIdempotencyFingerprint } from './idempotency'undefined(not exported)amount)Datevs. the equivalent ISO stringIDEMPOTENCY_HASH_THRESHOLD_BYTEShashv1:<sha256>digestSolution
Restore the fingerprint helper exactly as it was before the refactor: same function names and signatures, same behaviour, so fingerprints match those produced before the refactor. The helper builds a canonical string by sorting object keys at every level while keeping array order. It serialises
Datevalues as ISO-8601, and hashes the result with SHA-256 (prefixhashv1:) when it's larger than the configurable byte threshold (default 4096).Changes
backend/src/idempotency.tsRationale: this matches the pre-refactor implementation (
git show 5db5f6e0^:backend/src/idempotency.ts) line for line, so there's no change in fingerprint format or behaviour.cryptowas already imported. The code is appended at the end of the file and doesn't touch the refactor's Prisma-backed record API.backend/src/__tests__/idempotencyFingerprint.test.ts(new)A focused suite that imports only the helper, so it doesn't depend on any other part of
idempotency.ts. It checks that the helper is exported, that fingerprints are stable, and that the threshold behaves as expected.Regression Tests
is exported from idempotency.ts for the transfer orchestratorproduces the same fingerprint for a retry with reordered keysis deterministic across repeated calls and cloned payloadsdistinguishes payloads that differ in value,treats array order as significantserialises Dates as ISO strings and handles primitives and nullhashes payloads above the threshold into a stable, key-order-independent digestdefaults the hash threshold to 4096 bytes,keeps payloads at or below the threshold as their stable string formTesting
The same suite with the
idempotency.tschange reverted:npx tsc --noEmitreports no errors inidempotency.tsor the new test file.Notes for Reviewers
transferOrchestrator.tsalso importsidempotencyStore,IdempotencyConflictErrorandIdempotentOperationResult, which the same refactor removed. Restoring those is separate work (the idempotency response store, related to idempotency retention sweep lacks a dry-run safe path for production rehearsals #1375). End-to-end transfer retry safety needs both changes.idempotency.ts; resolve it by keeping a single copy.hashv1:prefix, 4096-byte default) is unchanged.git revertworks; the change leaves no persisted state behind.mainat 711c433 before this change (Backend Governance, Test Coverage, CodeQL, Flaky Test Detector, dependency audits).Closes #1376