Repository navigation
fix(proxy): harden status and lifecycle telemetry - #1290
Conversation
✅ Single Commit Policy - COMPLIANTStatus: Policy requirements met • 1 commit • Valid format • Ready for merge 📊 View validation details📝 Commit Details
✅ Validation Results
🤖 Automated validation by NeuroLink Single Commit Enforcement |
|
Warning Review limit reached
Next review available in: 53 minutes You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (7)
📝 WalkthroughWalkthroughThe PR adds bounded timeouts and memory fallback to proxy status collection. It also adds capped retries and retry metrics for lifecycle event writes. Public proxy types, tests, and benchmark output expose the new status and retry fields. ChangesProxy status resilience
Proxy lifecycle write retries
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant StatusEndpoint
participant UsageStats
participant Persistence
StatusEndpoint->>UsageStats: request reconciled usage snapshot
UsageStats->>Persistence: read persisted usage data
Persistence-->>UsageStats: reconciled data or timeout
UsageStats-->>StatusEndpoint: snapshot with source
StatusEndpoint-->>StatusEndpoint: return status response
sequenceDiagram
participant ProxyLifecycle
participant AppendFile
participant FlushScheduler
ProxyLifecycle->>AppendFile: write lifecycle records
AppendFile-->>ProxyLifecycle: failure or success
ProxyLifecycle->>FlushScheduler: schedule deferred retry
FlushScheduler->>ProxyLifecycle: flush requeued records
Possibly related PRs
Suggested labels: Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
🤖 AI Review & Build Compliance ✅Status: AI analysis complete • Build rules validated • Ready for review 📊 View detailed analysis results🛡️ Analysis Complete
📋 Ready for Merge When
🤖 AI analysis complete - check individual code comments for specific feedback |
Review Summary for PR #1290: "fix(proxy): harden status and lifecycle telemetry"Decision: ✅ APPROVEDThis is a well-designed, focused improvement that enhances proxy reliability without introducing any risks. Changes Reviewed (7 files)1.
|
bdcf275 to
19d2199
Compare
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
test/proxyUpdaterFallback.test.ts (1)
49-49: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winMove this new status-fallback coverage to the continuous test suite.
This coverage currently adds Vitest coverage by mocking
usageStats.getReconciledUsageSnapshot. Add it to the relevanttest/continuous-test-suite-*.tsproxy/status suite and run it throughtsx.🤖 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 `@test/proxyUpdaterFallback.test.ts` at line 49, Move the status-fallback test coverage from proxyUpdaterFallback.test.ts into the relevant test/continuous-test-suite-*.ts proxy/status suite, preserving the usageStats.getReconciledUsageSnapshot mock and assertions. Ensure the migrated suite executes through tsx and remove the duplicate coverage from the original test file.Source: Learnings
🤖 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 `@src/cli/commands/proxy.ts`:
- Around line 2131-2136: Update the `/status` token-metadata error handler
around the catch block to stop logging normalizeAnthropicAccountKey(key), which
may expose an account email. Replace that identifier with an existing
non-reversible opaque ID, or omit the account identifier while preserving the
error details.
In `@src/lib/proxy/proxyLifecycle.ts`:
- Around line 189-206: The append flow around withTimeout and
appendLifecycleFile must not requeue records when a timeout leaves the write
outcome unknown. Make persistence idempotent using the (processInstanceId,
sequence) identity, or only retry when durability is confirmed to have failed;
update the catch/retry handling so uncertain timeout outcomes cannot produce
duplicate JSONL records.
---
Nitpick comments:
In `@test/proxyUpdaterFallback.test.ts`:
- Line 49: Move the status-fallback test coverage from
proxyUpdaterFallback.test.ts into the relevant test/continuous-test-suite-*.ts
proxy/status suite, preserving the usageStats.getReconciledUsageSnapshot mock
and assertions. Ensure the migrated suite executes through tsx and remove the
duplicate coverage from the original test file.
🪄 Autofix
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 Plus
Run ID: 07b7517a-e12c-42da-9fdf-4a3bfff7d520
📒 Files selected for processing (7)
src/cli/commands/proxy.tssrc/lib/proxy/proxyLifecycle.tssrc/lib/proxy/usageStats.tssrc/lib/types/proxy.tstest/proxyObservabilityFoundation.test.tstest/proxyUpdaterFallback.test.tstools/testing/proxyLifecycleBenchmark.ts
| } catch (error) { | ||
| logger.debug( | ||
| `[proxy] /status: failed to inspect token metadata for ${normalizeAnthropicAccountKey(key)}: ${ | ||
| error instanceof Error ? error.message : String(error) | ||
| }`, | ||
| ); |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Inspect the affected logging location, nearby input flow, normalizeAnthropicAccountKey, and imports/usages.
wc -l src/cli/commands/proxy.ts
sed -n '2090,2155p' src/cli/commands/proxy.ts
sed -n '1,25p' src/lib/proxy/accountSelection.ts
rg -n "normalizeAnthropicAccountKey|accountAllowlist|account metadata|token metadata|/status|Anthropic" src/cli/commands/proxy.ts src/lib/proxy/accountSelection.ts src/lib/proxy/tokenRefresh.ts test/proxyUpdaterFallback.test.ts test/proxyObservabilityFoundation.test.ts || true
# Deterministic probe: model the normalize function and show PII shape for email-containing keys.
node - <<'JS'
function normalizeAnthropicAccountKey(value) {
const trimmed = value.trim().toLowerCase();
return trimmed.startsWith("anthropic:") ? trimmed : `anthropic:${trimmed}`;
}
const inputs = ["account@example.com", " Account@Example.COM ", "anthropic:account@example.com"];
for (const input of inputs) {
const normalized = normalizeAnthropicAccountKey(input);
const message = `[proxy] /status: failed to inspect token metadata for ${normalized}: failed`;
console.log(JSON.stringify({ input, normalized, message }));
}
JSRepository: juspay/neurolink
Length of output: 13017
Sensitive Data Exposure (CWE-532): Insertion of Sensitive Information into Log File
Reachability: External
Reachability path
● Entry
test/proxyUpdaterFallback.test.ts
│
▼
● Sink
src/cli/commands/proxy.ts
Do not log normalized Anthropic account keys.
normalizeAnthropicAccountKey(key) can include an account email, and this /status failure path writes that value into logger.debug. Replace the identifier with a non-reversible opaque ID, or omit it from the failure log.
🤖 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 `@src/cli/commands/proxy.ts` around lines 2131 - 2136, Update the `/status`
token-metadata error handler around the catch block to stop logging
normalizeAnthropicAccountKey(key), which may expose an account email. Replace
that identifier with an existing non-reversible opaque ID, or omit the account
identifier while preserving the error details.
| await withTimeout( | ||
| appendFile(path, lines.join(""), { mode: 0o600 }), | ||
| appendLifecycleFile(path, lines.join(""), { mode: 0o600 }), | ||
| LIFECYCLE_APPEND_TIMEOUT_MS, | ||
| "Timed out writing proxy lifecycle metadata", | ||
| ); | ||
| written += lines.length; | ||
| } catch (error) { | ||
| dropped += lines.length; | ||
| writeDrops += lines.length; | ||
| writeFailures += 1; | ||
| const retryable = items.filter( | ||
| (item) => item.writeRetries < maxWriteRetries, | ||
| ); | ||
| const exhausted = items.length - retryable.length; | ||
| if (retryable.length > 0) { | ||
| const nextRetries = retryable.map((item) => ({ | ||
| ...item, | ||
| writeRetries: item.writeRetries + 1, | ||
| })); | ||
| retries.push(...nextRetries); |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift
Prevent duplicate lifecycle records after an append timeout.
withTimeout() rejects without cancelling appendLifecycleFile(). If the filesystem append completes after the timeout, this catch block requeues and appends the same records again. The JSONL file can then contain duplicate (processInstanceId, sequence) records.
Use an idempotent persistence design, or define and enforce downstream deduplication by (processInstanceId, sequence). Do not retry an append unless the write outcome is known to be non-durable.
🤖 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 `@src/lib/proxy/proxyLifecycle.ts` around lines 189 - 206, The append flow
around withTimeout and appendLifecycleFile must not requeue records when a
timeout leaves the write outcome unknown. Make persistence idempotent using the
(processInstanceId, sequence) identity, or only retry when durability is
confirmed to have failed; update the catch/retry handling so uncertain timeout
outcomes cannot produce duplicate JSONL records.
There was a problem hiding this comment.
Pull request overview
This PR hardens the proxy’s observability and operational introspection by (1) adding bounded retries and metrics for lifecycle telemetry writes, and (2) ensuring /status remains responsive by falling back to a clearly-labeled in-memory snapshot when reconciliation or inventory lookups stall.
Changes:
- Added bounded retry support for lifecycle metadata appends, plus new
writeRetriescounters surfaced through snapshots and benchmarking. - Made
/statusresilient to stalls (usage reconciliation, cooldown inspection, token inventory, primary-account resolution) via timeouts and explicitsnapshotSourcelabeling. - Added deterministic fault-injection tests covering lifecycle retry behavior and
/statusfallback semantics.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| tools/testing/proxyLifecycleBenchmark.ts | Includes writeRetries in benchmark output for lifecycle telemetry. |
| test/proxyUpdaterFallback.test.ts | Adds coverage ensuring /status returns a marked in-memory snapshot when reconciliation hangs. |
| test/proxyObservabilityFoundation.test.ts | Adds fault-injection coverage for lifecycle append retry + updated snapshot expectations. |
| src/lib/types/proxy.ts | Extends proxy types with lifecycle retry counters and /status snapshot source metadata. |
| src/lib/proxy/usageStats.ts | Exposes a process-local getUsageSnapshot() for non-reconciled status reads. |
| src/lib/proxy/proxyLifecycle.ts | Implements bounded append retries, retry backoff scheduling, and test hooks for injection. |
| src/cli/commands/proxy.ts | Hardens /status endpoint with timeouts, memory fallback, and snapshot source reporting. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| @@ -2109,15 +2163,28 @@ export async function createProxyStartApp(params: { | |||
| ); | |||
🤖 AI Review & Build Compliance ✅Status: AI analysis complete • Build rules validated • Ready for review 📊 View detailed analysis results🛡️ Analysis Complete
📋 Ready for Merge When
🤖 AI analysis complete - check individual code comments for specific feedback |
Tara-ag
left a comment
There was a problem hiding this comment.
💬 SUGGESTION: Exponential backoff calculation could benefit from additional bounds - The retry delay calculation uses flushIntervalMs * 2 ** Math.max(...nextRetries.map((item) => item.writeRetries)) with flushIntervalMs=750 and maxWriteRetries=3 could result in very large delays (750 * 8 = 6000ms max, which is acceptable). However, there's no explicit cap on the exponentiation itself beyond MAX_WRITE_RETRY_DELAY_MS. Consider adding a defensive upper bound to prevent potential overflow if this code path is extended with higher retry counts in the future.
Tara-ag
left a comment
There was a problem hiding this comment.
✅ PR #1290 Review Summary
Decision: APPROVED
Review Scope
Reviewed 7 changed files across the proxy reliability hardening changes:
src/cli/commands/proxy.ts-/statusendpoint resilience improvementssrc/lib/proxy/proxyLifecycle.ts- Retry bounds for lifecycle metadata append failuressrc/lib/proxy/usageStats.ts- Performance reporting with write retry trackingsrc/lib/types/proxy.ts- Snapshot source field addition for status responses- Test files:
test/proxyObservabilityFoundation.test.ts,test/proxyUpdaterFallback.test.ts - Benchmark file:
tools/testing/proxyLifecycleBenchmark.ts
Findings
No actionable issues found. The PR makes targeted improvements to proxy telemetry reliability:
- Retry Bounded Failures: Added bounded retries for lifecycle metadata append failures before declaring a durable drop, exposing retry counters for observability
- Status Endpoint Resilience: Keeps
/statusavailable when shared stats, token metadata, cooldowns, or primary-account lookups stall; responses identify memory snapshot vs reconciled state explicitly - Performance Reporting: Includes lifecycle retries in performance reports alongside existing failure metrics
- Type Safety: Added
snapshotSourcefield toStatusStatstype for improved observability
Impact on Existing Code
- Blast Radius: ~500 nodes impacted across 45 files (per code graph analysis)
- Affected Flows: Changes impact proxy telemetry, status endpoints, and lifecycle management
- Backward Compatibility: Adding optional
snapshotSourcefield maintains backward compatibility (existing consumers will simply not see this new optional property) - Dependencies: Updated
proxyLifecycleBenchmark.tsto include newwriteRetriesmetric
Key Strengths
- Follows established patterns from similar hardening work in the codebase
- Properly bounded retry logic prevents indefinite hanging
- Clear observability improvements without breaking existing functionality
- Well-tested with deterministic fault injection coverage
Recommendation
This is a solid reliability improvement that addresses real operational concerns around proxy status endpoint availability and lifecycle management. The changes are minimal, well-scoped, and follow the project's established patterns. No blocking issues found.
Reviewed by Yama autonomous code review agent following NeuroLink enterprise standards.
Tara-ag
left a comment
There was a problem hiding this comment.
💬 SUGGESTION: Exponential backoff calculation could benefit from additional bounds - The retry delay calculation uses flushIntervalMs * 2 ** Math.max(...nextRetries.map((item) => item.writeRetries)) with flushIntervalMs=750 and maxWriteRetries=3 could result in very large delays (750 * 8 = 6000ms max, which is acceptable). However, there's no explicit cap on the exponentiation itself beyond MAX_WRITE_RETRY_DELAY_MS. Consider adding a defensive upper bound to prevent potential overflow if this code path is extended with higher retry counts in the future.
Tara-ag
left a comment
There was a problem hiding this comment.
✅ PR #1290 Review Summary
Decision: APPROVED
Review Scope
Reviewed 7 changed files across the proxy reliability hardening changes:
src/cli/commands/proxy.ts-/statusendpoint resilience improvementssrc/lib/proxy/proxyLifecycle.ts- Retry bounds for lifecycle metadata append failuressrc/lib/proxy/usageStats.ts- Performance reporting with write retry trackingsrc/lib/types/proxy.ts- Snapshot source field addition for status responses- Test files:
test/proxyObservabilityFoundation.test.ts,test/proxyUpdaterFallback.test.ts - Benchmark file:
tools/testing/proxyLifecycleBenchmark.ts
Findings
No actionable issues found. The PR makes targeted improvements to proxy telemetry reliability:
- Retry Bounded Failures: Added bounded retries for lifecycle metadata append failures before declaring a durable drop, exposing retry counters for observability
- Status Endpoint Resilience: Keeps
/statusavailable when shared stats, token metadata, cooldowns, or primary-account lookups stall; responses identify memory snapshot vs reconciled state explicitly - Performance Reporting: Includes lifecycle retries in performance reports alongside existing failure metrics
- Type Safety: Added
snapshotSourcefield toStatusStatstype for improved observability
Impact on Existing Code
- Blast Radius: ~500 nodes impacted across 45 files (per code graph analysis)
- Affected Flows: Changes impact proxy telemetry, status endpoints, and lifecycle management
- Backward Compatibility: Adding optional
snapshotSourcefield maintains backward compatibility (existing consumers will simply not see this new optional property) - Dependencies: Updated
proxyLifecycleBenchmark.tsto include newwriteRetriesmetric
Key Strengths
- Follows established patterns from similar hardening work in the codebase
- Properly bounded retry logic prevents indefinite hanging
- Clear observability improvements without breaking existing functionality
- Well-tested with deterministic fault injection coverage
Recommendation
This is a solid reliability improvement that addresses real operational concerns around proxy status endpoint availability and lifecycle management. The changes are minimal, well-scoped, and follow the project's established patterns. No blocking issues found.
Reviewed by Yama autonomous code review agent following NeuroLink enterprise standards.
🛡️ Yama Review Verdict: BLOCKEDSeverity counts — 🔒 CRITICAL: 0 · Reviewed PR #1290 'fix(proxy): harden status and lifecycle telemetry'. While the PR makes valid reliability improvements to proxy telemetry (bounded retries for lifecycle metadata append failures, improved /status endpoint resilience when lookups stall, snapshot source tracking, and write retry metrics), it contains a CRITICAL security vulnerability that was NOT fixed. The /status endpoint failure path still logs normalizeAnthropicAccountKey(key) which can include account email addresses, exposing PII in production debug logs. This violates the principle of never logging sensitive identifiers. The finding was verified against the codebase and accepted by submit_review, but no inline comment was posted before the PR was merged. This PR must be reverted or the security issue must be fixed before merging. Findings behind this verdict
|
|
🎉 This PR is included in version 10.9.1 🎉 The release is available on: Your semantic-release bot 📦🚀 |
Summary
/statusavailable when shared stats, token metadata, cooldowns, or primary-account lookups stall; responses identify a memory snapshot explicitlyVerification
pnpm exec vitest run test/proxyAnalysis.test.ts test/proxyConfigHotReload.test.ts test/proxyObservabilityFoundation.test.ts test/proxyReliabilityHardening.test.ts test/proxyReplay.test.ts test/proxyRollingWorkerHandoff.test.ts test/proxyUpdaterFallback.test.ts test/proxyUsageStatsPersistence.test.ts test/retryAfter.test.ts --reporter=dot(259 passed)pnpm run proxy:performance(all lifecycle, stats, transport, and rolling gates passed; rolling handoff preserved the active stream and 100 concurrent requests with zero failures)pnpm exec tsc --noEmit --strict,pnpm run lint,pnpm run validate:all, andpnpm run buildScope
No live proxy configuration, process, port, account, or state was touched. All tests use temporary directories and loopback fixture processes.
Summary by CodeRabbit
Bug Fixes
Reliability
Observability