Skip to content
GitLab
Projects Groups Topics Snippets
  • /
  • Help
    • Help
    • Support
    • Community forum
    • Submit feedback
    • Contribute to GitLab
  • Register
  • Sign in
  • A Ahad Mobile
  • Project information
    • Project information
    • Activity
    • Labels
    • Members
  • Repository
    • Repository
    • Files
    • Commits
    • Branches
    • Tags
    • Contributor statistics
    • Graph
    • Compare revisions
  • Issues 0
    • Issues 0
    • List
    • Boards
    • Service Desk
    • Milestones
  • Merge requests 0
    • Merge requests 0
  • CI/CD
    • CI/CD
    • Pipelines
    • Jobs
    • Schedules
  • Deployments
    • Deployments
    • Environments
    • Releases
  • Packages and registries
    • Packages and registries
    • Package Registry
    • Terraform modules
  • Monitor
    • Monitor
    • Incidents
  • Analytics
    • Analytics
    • Value stream
    • CI/CD
    • Repository
  • Wiki
    • Wiki
  • Snippets
    • Snippets
  • Activity
  • Graph
  • Create a new issue
  • Jobs
  • Commits
  • Issue Boards
Collapse sidebar
  • holatech
  • Ahad Mobile
  • Merge requests
  • !97

fix(keysecure): post truncated-time consumption success, parse card_update, retry client token on 1007

  • Review changes

  • Download
  • Patches
  • Plain diff
Merged Khanh Pham requested to merge fix/keysecure-webhook-time-and-1007 into develop Oct 05, 2026
  • Overview 0
  • Commits 5
  • Pipelines 1
  • Changes 8

Why

Staging evidence on 2026-10-05:

  • Card fee lost (A). For Open_card CC261005QYMFP2IO, the Pending webhook arrived with time …523178 ms, then the Success webhook with time …523000 ms: KeySecure truncated the Success time to whole seconds. The strict millisecond guard treated Success as older, so the 2 USD card fee was never posted.
  • Card_update never parsed (B). Real Card_update payloads have no before_status, so every one failed with bad_card_update.
  • Card details failed intermittently (C). The one-time client-token call got 1007 (Access-Token invalid or expired) and was never retried, so the app showed a 502.

Changes

  • card-consumption.service.ts
    • Consumption events are compared at whole-second precision.
    • Within the same second a Success wins over a Fail: a Fail after a stored Success is ignored, and a Success after a stored Fail still posts.
    • A late Pending still never downgrades a settled row.
    • Posting stays delta-based under the row lock, so nothing can double-post.
  • keysecure-webhook.parser.ts: before_status is optional.
  • keysecure-http.client.ts
    • An issue-once request (client token) is retried once after a 1006/1007 auth rejection.
    • This is safe because any token minted by the rejected attempt never reached us and expires unused.
    • write-unkeyed is still never retried, and a 5xx or timeout is still outcome-unknown.

Tests

  • Unit tests:
    • the truncated Success posts;
    • an event from an earlier second is ignored;
    • same-second Fail-after-Success is ignored, and Success-after-Fail posts;
    • the real Card_update payload parses;
    • issue-once 1007 is retried once.
  • Postgres spec reproducing the staging sequence for an Open_card.
  • yarn jest src/modules/card-account src/modules/keysecure: 607 pass, 12 skipped (DB specs).
  • card-consumption.postgres.spec.ts on moanapay_test: 6/6 pass.
  • eslint and yarn build are clean.
  • Each new assertion was mutation-checked.
  • Opus review gate: PASS after 3 rounds.

Known gap (pre-existing, out of scope)

A Fail arriving in a later second than a Success still flips the status without reversing the debit. KeySecure does not document that sequence.

After deploy

The lost staging fee can be re-posted by setting webhook CN2610054D2EIHOG back to FAILED so the replay scheduler reprocesses it. That step needs separate approval.

🤖 Generated with Claude Code

Assignee
Assign to
Reviewers
Request review from
Time tracking
Source branch: fix/keysecure-webhook-time-and-1007