Skip to content

feat: add events observability to POS#243

Merged
jakubuid merged 4 commits intodevelopfrom
feat/pos_observability
Dec 29, 2025
Merged

feat: add events observability to POS#243
jakubuid merged 4 commits intodevelopfrom
feat/pos_observability

Conversation

@jakubuid
Copy link
Collaborator

No description provided.

@claude
Copy link

claude bot commented Dec 19, 2025

Claude finished @jakubuid's task in 1m 27s —— View job


Code Review

Issue 1: Unsafe force unwrap causes potential crash

ID: posclient-force-unwrap-crash-3c9f
File: product/pos/src/main/kotlin/com/walletconnect/pos/PosClient.kt:41
Severity: HIGH
Category: code_quality

The force unwrap operator eventTracker!! creates a potential crash if EventTracker construction throws an exception. Although EventTracker is assigned on the previous line, any exception during initialization leaves eventTracker null while apiClient tries to use it.

Recommendation: Use safer initialization pattern:

val newScope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
this.scope = newScope
val tracker = EventTracker(merchantId, newScope)
this.eventTracker = tracker
this.apiClient = ApiClient(apiKey, merchantId, tracker)

Issue 2: Currency parsing logic assumes specific format

ID: eventmodels-currency-parse-assumes-5a2f
File: product/pos/src/main/kotlin/com/walletconnect/pos/api/EventModels.kt:54
Severity: MEDIUM
Category: code_quality

The currency extraction unit.substringAfter("/", "") assumes a specific format like "eip155:1/erc20:0x..." and silently returns empty string if no "/" exists. This could lead to missing currency data in telemetry.

Recommendation: Add validation or fallback:

val currency = if (unit.contains("/")) {
    unit.substringAfter("/")
} else {
    unit // use full unit as currency if no "/" present
}

Issue 3: Integer division truncates fractional amounts

ID: eventmodels-division-truncates-amount-8d41
File: product/pos/src/main/kotlin/com/walletconnect/pos/api/EventModels.kt:55
Severity: MEDIUM
Category: code_quality

The calculation valueMinor / 100.0 assumes all currencies use 2 decimal places. Cryptocurrencies and different fiat currencies may use different decimal places (e.g., 18 decimals for ETH, 0 for JPY).

Recommendation: Either document this assumption or make decimal places configurable based on currency type. At minimum, add a comment explaining the 2-decimal assumption.


Issue 4: Exception handler only prints to stdout

ID: eventtracker-exception-handler-stdout-2b7e
File: product/pos/src/main/kotlin/com/walletconnect/pos/api/EventTracker.kt:57
Severity: LOW
Category: code_quality

The silentExceptionHandler uses println(t) which may not be captured in production logging systems. In production builds, these exceptions are lost.

Recommendation: Use proper logging:

private val silentExceptionHandler = CoroutineExceptionHandler { _, t -> 
    if (BuildConfig.DEBUG) {
        Log.w("EventTracker", "Event tracking failed", t)
    }
}

Issue 5: Missing null-safety check on scope launch

ID: eventtracker-scope-null-launch-4f3a
File: product/pos/src/main/kotlin/com/walletconnect/pos/api/EventTracker.kt:145
Severity: LOW
Category: code_quality

The scope.launch() call doesn't handle the case where the scope might be cancelled between the try-catch and the launch call, though this is unlikely given the try-catch wraps it.

Recommendation: Current implementation is acceptable, but consider adding documentation that this scope is expected to be active for the tracker's lifetime.


Issue 6: Potential memory leak with coroutine scope

ID: posclient-scope-leak-cleanup-9a1c
File: product/pos/src/main/kotlin/com/walletconnect/pos/PosClient.kt:124
Severity: MEDIUM
Category: code_quality

The cleanup() method cancels the scope but doesn't wait for child coroutines to complete. If EventTracker has ongoing network requests during shutdown, they may continue executing briefly, potentially accessing cleaned-up resources.

Recommendation: Consider using scope?.cancel() followed by checking if critical cleanup is needed, or document that event tracking may continue briefly after shutdown (which appears intentional based on fire-and-forget design).


Issue 7: Date formatting not thread-safe

ID: eventtracker-date-format-thread-unsafe-6c8d
File: product/pos/src/main/kotlin/com/walletconnect/pos/api/EventTracker.kt:53
Severity: HIGH
Category: code_quality

SimpleDateFormat is not thread-safe, but it's used as a shared instance field that can be accessed from multiple coroutines launched on different threads via scope.launch(Dispatchers.IO).

Recommendation: Use thread-safe date formatting:

// Option 1: Create new formatter per use
private fun formatTimestamp(): String {
    return SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US).apply {
        timeZone = TimeZone.getTimeZone("UTC")
    }.format(Date())
}

// Option 2: Use Java 8+ DateTimeFormatter if minSdk allows
private val isoDateFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
    .withZone(ZoneId.of("UTC"))

Automated Checks

✅ No external domain URLs detected
✅ No static resource cache-control issues detected
✅ No GitHub Actions workflow security issues detected


val newScope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
this.scope = newScope
this.eventTracker = EventTracker(merchantId, newScope)
this.apiClient = ApiClient(apiKey, merchantId, eventTracker!!)

Choose a reason for hiding this comment

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

🤖 Auto Review Issue: Unsafe force unwrap causes potential crash

Severity: HIGH
Category: code_quality
Tool: Claude Auto Review

Recommendation: Use safer initialization pattern:

val newScope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
this.scope = newScope
val tracker = EventTracker(merchantId, newScope)
this.eventTracker = tracker
this.apiClient = ApiClient(apiKey, merchantId, tracker)

@claude
Copy link

claude bot commented Dec 19, 2025

Claude finished @jakubuid's task in 1m 3s —— View job


🔄 Incremental Review:

Verified Status of Previously Reported Issues

✅ RESOLVED: Issue 1 - Unsafe force unwrap

Previous ID: posclient-force-unwrap-crash-3c9f
Previous Location: PosClient.kt:41
Status: Fixed - force unwrap removed, proper initialization pattern implemented at lines 42-44


Issue 2: Currency parsing logic assumes specific format

ID: eventmodels-currency-parse-assumes-5a2f
File: product/pos/src/main/kotlin/com/walletconnect/pos/api/EventModels.kt:54
Severity: MEDIUM
Category: code_quality

Confirmed still present - Logic at line 54 still uses substringAfter("/", "") without validation, returning empty string if no "/" exists.

Recommendation: Add validation:

val currency = if (unit.contains("/")) {
    unit.substringAfter("/")
} else {
    unit // use full unit as currency if no "/" present
}

Issue 3: Integer division truncates fractional amounts

ID: eventmodels-division-truncates-amount-8d41
File: product/pos/src/main/kotlin/com/walletconnect/pos/api/EventModels.kt:55
Severity: MEDIUM
Category: code_quality

Confirmed still present - Calculation valueMinor / 100.0 at line 55 assumes all currencies use 2 decimal places. Also present at EventTracker.kt:71.

Recommendation: Document the 2-decimal assumption:

// Assumes valueMinor uses 2 decimal places (standard for most fiat currencies)
val displayAmount = valueMinor / 100.0

Issue 4: Exception handler only prints to stdout

ID: eventtracker-exception-handler-stdout-2b7e
File: product/pos/src/main/kotlin/com/walletconnect/pos/api/EventTracker.kt:57
Severity: LOW
Category: code_quality

Confirmed still present - Line 57 uses println(t) which won't be captured in production logging. Also duplicated in ErrorTracker.kt:47.

Recommendation: Use proper logging:

private val silentExceptionHandler = CoroutineExceptionHandler { _, t -> 
    if (BuildConfig.DEBUG) {
        Log.w("EventTracker", "Event tracking failed", t)
    }
}

✅ RESOLVED: Issue 5 - Missing null-safety check on scope launch

Previous ID: eventtracker-scope-null-launch-4f3a
Previous Location: EventTracker.kt:145
Status: No longer flagged as issue - implementation acceptable


✅ RESOLVED: Issue 6 - Potential memory leak with coroutine scope

Previous ID: posclient-scope-leak-cleanup-9a1c
Previous Location: PosClient.kt:124
Status: Fixed - cleanup method at lines 124-132 properly handles scope cancellation and resource cleanup


Issue 7: Date formatting not thread-safe

ID: eventtracker-date-format-thread-unsafe-6c8d
File: product/pos/src/main/kotlin/com/walletconnect/pos/api/EventTracker.kt:53
Severity: HIGH
Category: code_quality

Confirmed still present - SimpleDateFormat instance at line 53 is shared across multiple coroutines on IO dispatcher (line 145), creating thread-safety risk.

Recommendation: Use thread-safe date formatting:

// Option 1: Create new formatter per use
private fun formatTimestamp(): String {
    return SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US).apply {
        timeZone = TimeZone.getTimeZone("UTC")
    }.format(Date())
}

// Option 2: Use synchronized access
private fun formatTimestamp(): String {
    synchronized(isoDateFormat) {
        return isoDateFormat.format(Date())
    }
}

Summary

Resolved: 3 issues fixed since last review
Still Present: 4 issues remain (2 HIGH, 2 MEDIUM, 0 LOW)
New Issues: 0

@claude
Copy link

claude bot commented Dec 29, 2025

Claude finished @jakubuid's task in 1m 26s —— View job


🔄 Incremental Review:

Verified Status of Previously Reported Issues

✅ RESOLVED: Issue 1 - Unsafe force unwrap

Previous ID: posclient-force-unwrap-crash-3c9f
Status: Fixed in previous commits


Issue 2: Currency parsing logic assumes specific format

ID: eventmodels-currency-parse-assumes-5a2f
File: product/pos/src/main/kotlin/com/walletconnect/pos/api/EventModels.kt:54
Severity: MEDIUM
Category: code_quality

Confirmed still present - Logic at line 54 uses substringAfter("/", "") without validation, returning empty string if no "/" exists. Also duplicated at EventTracker.kt:70.

Recommendation: Add validation:

val currency = if (unit.contains("/")) {
    unit.substringAfter("/")
} else {
    unit // use full unit as currency if no "/" present
}

Issue 3: Integer division truncates fractional amounts

ID: eventmodels-division-truncates-amount-8d41
File: product/pos/src/main/kotlin/com/walletconnect/pos/api/EventModels.kt:55
Severity: MEDIUM
Category: code_quality

Confirmed still present - Calculation valueMinor / 100.0 at line 55 assumes all currencies use 2 decimal places. Also duplicated at EventTracker.kt:71.

Recommendation: Document the 2-decimal assumption:

// Assumes valueMinor uses 2 decimal places (standard for most fiat currencies)
val displayAmount = valueMinor / 100.0

Issue 4: Exception handler only prints to stdout

ID: eventtracker-exception-handler-stdout-2b7e
File: product/pos/src/main/kotlin/com/walletconnect/pos/api/EventTracker.kt:57
Severity: LOW
Category: code_quality

Confirmed still present - Line 57 uses println(t) which won't be captured in production logging. Also duplicated in ErrorTracker.kt:47.

Recommendation: Use proper logging:

private val silentExceptionHandler = CoroutineExceptionHandler { _, t -> 
    if (BuildConfig.DEBUG) {
        Log.w("EventTracker", "Event tracking failed", t)
    }
}

✅ RESOLVED: Issue 5 - Missing null-safety check

Previous ID: eventtracker-scope-null-launch-4f3a
Status: No longer flagged


✅ RESOLVED: Issue 6 - Potential memory leak

Previous ID: posclient-scope-leak-cleanup-9a1c
Status: Fixed in previous commits


Issue 7: Date formatting not thread-safe

ID: eventtracker-date-format-thread-unsafe-6c8d
File: product/pos/src/main/kotlin/com/walletconnect/pos/api/EventTracker.kt:53
Severity: HIGH
Category: code_quality

Confirmed still present - SimpleDateFormat instance at line 53 is shared across multiple coroutines on IO dispatcher (line 145), creating thread-safety risk.

Recommendation: Create formatter per use:

private fun formatTimestamp(): String {
    return SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US).apply {
        timeZone = TimeZone.getTimeZone("UTC")
    }.format(Date())
}

Issue 8: Missing comma in workflow matrix

ID: debugsample-matrix-syntax-error-4a9b
File: .github/workflows/ci_debug_sample.yml:13
Severity: HIGH
Category: code_quality

Workflow syntax error - missing comma after line 13 before line 14 in matrix definition causes YAML parsing failure.

Recommendation: Add comma:

{ name: modal, command: ":sample:modal:assembleDebug :sample:modal:appDistributionUploadDebug" },
{ name: pos, command: ":sample:pos:assembleDebug" }

Issue 9: Missing comma in workflow matrix

ID: internalsample-matrix-syntax-error-7c2d
File: .github/workflows/ci_internal_sample.yml:22
Severity: HIGH
Category: code_quality

Workflow syntax error - missing comma after line 22 before line 23 in matrix definition causes YAML parsing failure.

Recommendation: Add comma:

{ name: modal, command: ":sample:modal:assembleInternal :sample:modal:appDistributionUploadInternal" },
{ name: pos, command: ":sample:pos:assembleInternal" }

Summary

Resolved: 3 issues fixed since last review
Still Present: 4 issues remain (2 HIGH, 2 MEDIUM, 1 LOW)
New Issues: 2 HIGH severity workflow syntax errors


Automated Checks

✅ No external domain URLs detected
✅ No static resource cache-control issues detected
✅ No GitHub Actions workflow security issues detected

@claude
Copy link

claude bot commented Dec 29, 2025

Claude finished @jakubuid's task in 1m 20s —— View job


🔄 Incremental Review:

Verified Status of Previously Reported Issues

✅ RESOLVED: Issue 1 - Unsafe force unwrap

Previous ID: posclient-force-unwrap-crash-3c9f
Status: Fixed - safer initialization pattern implemented at PosClient.kt:40-44


✅ RESOLVED: Issue 2 - Currency parsing logic assumes specific format

Previous ID: eventmodels-currency-parse-assumes-5a2f
Status: Fixed - proper if/else validation added at EventModels.kt:50-54


Issue 3: Integer division truncates fractional amounts

ID: eventmodels-division-truncates-amount-8d41
File: product/pos/src/main/kotlin/com/walletconnect/pos/api/EventModels.kt:56
Severity: MEDIUM
Category: code_quality

Confirmed still present - Calculation valueMinor / 100.0 assumes all currencies use 2 decimal places. Also duplicated at EventTracker.kt:70.

Recommendation: Document the 2-decimal assumption:

// Assumes valueMinor uses 2 decimal places (standard for most fiat currencies)
val displayAmount = valueMinor / 100.0

Issue 4: Exception handler only prints to stdout

ID: eventtracker-exception-handler-stdout-2b7e
File: product/pos/src/main/kotlin/com/walletconnect/pos/api/EventTracker.kt:61
Severity: LOW
Category: code_quality

Confirmed still present - Line 61 uses println(t) which won't be captured in production logging. Also duplicated in ErrorTracker.kt:47.

Recommendation: Use proper logging:

private val silentExceptionHandler = CoroutineExceptionHandler { _, t -> 
    if (BuildConfig.DEBUG) {
        Log.w("EventTracker", "Event tracking failed", t)
    }
}

✅ RESOLVED: Issue 7 - Date formatting not thread-safe

Previous ID: eventtracker-date-format-thread-unsafe-6c8d
Status: Fixed - isoDateFormat() function at EventTracker.kt:55-59 now creates new formatter instance per call


✅ RESOLVED: Issue 8 & 9 - Missing commas in workflow matrix

Previous IDs: debugsample-matrix-syntax-error-4a9b, internalsample-matrix-syntax-error-7c2d
Status: Fixed - proper commas added in both workflow files


Summary

Resolved: 5 issues fixed since last review
Still Present: 2 issues remain (1 MEDIUM, 1 LOW)
New Issues: 0


Automated Checks

✅ No external domain URLs detected
✅ No static resource cache-control issues detected
✅ No GitHub Actions workflow security issues detected

@sonarqubecloud
Copy link

Quality Gate Failed Quality Gate failed

Failed conditions
8.6% Duplication on New Code (required ≤ 3%)

See analysis details on SonarQube Cloud

@jakubuid jakubuid merged commit ddca8f1 into develop Dec 29, 2025
13 of 17 checks passed
@github-actions github-actions bot locked and limited conversation to collaborators Dec 29, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant