Abridge Debug Bundle
Overview
Collect HIPAA-safe diagnostic data for Abridge support tickets. All PHI is automatically redacted before bundle creation.
Prerequisites
- Abridge credentials configured
- Access to application logs
- Node.js or bash for running diagnostic scripts
Instructions
Step 1: Generate Debug Bundle
// src/debug/abridge-debug-bundle.ts
import fs from 'fs';
import { execSync } from 'child_process';
interface DebugBundle {
timestamp: string;
environment: Record<string, string>;
connectivity: Record<string, any>;
recentErrors: any[];
sessionDiagnostics: any[];
fhirStatus: any;
}
async function generateDebugBundle(): Promise<DebugBundle> {
const bundle: DebugBundle = {
timestamp: new Date().toISOString(),
environment: collectEnvironment(),
connectivity: await testConnectivity(),
recentErrors: await collectRecentErrors(),
sessionDiagnostics: await collectSessionDiagnostics(),
fhirStatus: await checkFhirStatus(),
};
// Redact PHI before saving
const sanitized = redactPhi(JSON.stringify(bundle, null, 2));
const filename = `abridge-debug-${Date.now()}.json`;
fs.writeFileSync(filename, sanitized);
console.log(`Debug bundle saved: ${filename}`);
return bundle;
}
function collectEnvironment(): Record<string, string> {
return {
nodeVersion: process.version,
platform: process.platform,
abridgeBaseUrl: process.env.ABRIDGE_BASE_URL || 'NOT SET',
orgId: process.env.ABRIDGE_ORG_ID ? 'SET (redacted)' : 'NOT SET',
clientSecret: process.env.ABRIDGE_CLIENT_SECRET ? 'SET (redacted)' : 'NOT SET',
fhirBaseUrl: process.env.EPIC_FHIR_BASE_URL || 'NOT SET',
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
};
}
async function testConnectivity(): Promise<Record<string, any>> {
const results: Record<string, any> = {};
const endpoints = [
{ name: 'abridge_api', url: `${process.env.ABRIDGE_BASE_URL}/health` },
{ name: 'fhir_server', url: `${process.env.EPIC_FHIR_BASE_URL}/metadata` },
];
for (const ep of endpoints) {
try {
const start = Date.now();
const res = await fetch(ep.url, { signal: AbortSignal.timeout(5000) });
results[ep.name] = { status: res.status, latency_ms: Date.now() - start };
} catch (err) {
results[ep.name] = { status: 'UNREACHABLE', error: (err as Error).message };
}
}
return results;
}
function redactPhi(text: string): string {
return text
.replace(/\b\d{3}-\d{2}-\d{4}\b/g, '[SSN-REDACTED]')
.replace(/\b\d{10}\b/g, '[MRN-REDACTED]')
.replace(/"(name|patient_name|given|family)":\s*"[^"]+"/g, '"$1": "[REDACTED]"')
.replace(/\b\d{1,2}\/\d{1,2}\/\d{2,4}\b/g, '[DOB-REDACTED]');
}
Step 2: Session-Level Diagnostics
async function collectSessionDiagnostics(): Promise<any[]> {
const api = AbridgeApiClient.getInstance().http;
try {
const { data } = await api.get('/encounters/sessions', {
params: { status: 'error', limit: 10, order: 'desc' },
});
return data.sessions.map((s: any) => ({
session_id: s.session_id,
status: s.status,
error_code: s.error_code,
specialty: s.specialty,
created_at: s.created_at,
segment_count: s.segment_count,
// No PHI fields included
}));
} catch {
return [{ error: 'Could not fetch session diagnostics' }];
}
}
Step 3: Bash Quick Diagnostic
#!/bin/bash
# scripts/abridge-quick-diag.sh
echo "=== Abridge Quick Diagnostics $(date -Iseconds) ==="
echo -e "\n--- Environment ---"
echo "ABRIDGE_BASE_URL: ${ABRIDGE_BASE_URL:-NOT SET}"
echo "ABRIDGE_ORG_ID: ${ABRIDGE_ORG_ID:+SET (redacted)}"
echo "ABRIDGE_CLIENT_SECRET: ${ABRIDGE_CLIENT_SECRET:+SET (redacted)}"
echo -e "\n--- Connectivity ---"
echo -n "API Health: "
curl -s -o /dev/null -w "%{http_code} (%{time_total}s)" \
-H "Authorization: Bearer $ABRIDGE_CLIENT_SECRET" \
-H "X-Org-Id: $ABRIDGE_ORG_ID" \
"$ABRIDGE_BASE_URL/health"
echo -e "\n\n--- TLS Info ---"
echo | openssl s_client -connect "$(echo $ABRIDGE_BASE_URL | sed 's|https://||'):443" 2>/dev/null \
| openssl x509 -noout -subject -dates 2>/dev/null
echo -e "\n--- DNS Resolution ---"
dig +short "$(echo $ABRIDGE_BASE_URL | sed 's|https://||')" 2>/dev/null || echo "dig not available"
echo -e "\n=== Diagnostics Complete ==="
Output
abridge-debug-{timestamp}.json file with all PHI redacted
- Environment configuration status
- Connectivity test results with latency
- Recent error sessions (metadata only, no PHI)
Error Handling
| Issue |
Cause |
Solution |
| Bundle contains PHI |
Redaction regex missed a pattern |
Add pattern to redactPhi() function |
| Cannot reach API |
Network/firewall issue |
Check DNS, TLS cert, firewall rules |
| Empty error list |
No recent errors |
Good sign — check if issue is client-side |
Resources
Next Steps
For rate limiting patterns, see abridge-rate-limits.
1---2name: abridge-debug-bundle3description: |4 Collect Abridge debug evidence for support tickets and troubleshooting.5 Use when filing Abridge support tickets, collecting diagnostic data,6 or preparing evidence for escalation to Abridge engineering.7 Trigger: "abridge debug bundle", "abridge support ticket",8 "abridge diagnostics", "collect abridge evidence".9allowed-tools: Read, Write, Edit, Bash(curl:*), Bash(node:*), Grep10version: 1.0.011license: MIT12author: Jeremy Longshore <jeremy@intentsolutions.io>13tags: [saas, healthcare, ai, abridge, debugging]14compatible-with: claude-code15---1617# Abridge Debug Bundle1819## Overview2021Collect HIPAA-safe diagnostic data for Abridge support tickets. All PHI is automatically redacted before bundle creation.2223## Prerequisites2425- Abridge credentials configured26- Access to application logs27- Node.js or bash for running diagnostic scripts2829## Instructions3031### Step 1: Generate Debug Bundle3233```typescript34// src/debug/abridge-debug-bundle.ts35import fs from 'fs';36import { execSync } from 'child_process';3738interface DebugBundle {39 timestamp: string;40 environment: Record<string, string>;41 connectivity: Record<string, any>;42 recentErrors: any[];43 sessionDiagnostics: any[];44 fhirStatus: any;45}4647async function generateDebugBundle(): Promise<DebugBundle> {48 const bundle: DebugBundle = {49 timestamp: new Date().toISOString(),50 environment: collectEnvironment(),51 connectivity: await testConnectivity(),52 recentErrors: await collectRecentErrors(),53 sessionDiagnostics: await collectSessionDiagnostics(),54 fhirStatus: await checkFhirStatus(),55 };5657 // Redact PHI before saving58 const sanitized = redactPhi(JSON.stringify(bundle, null, 2));59 const filename = `abridge-debug-${Date.now()}.json`;60 fs.writeFileSync(filename, sanitized);61 console.log(`Debug bundle saved: ${filename}`);6263 return bundle;64}6566function collectEnvironment(): Record<string, string> {67 return {68 nodeVersion: process.version,69 platform: process.platform,70 abridgeBaseUrl: process.env.ABRIDGE_BASE_URL || 'NOT SET',71 orgId: process.env.ABRIDGE_ORG_ID ? 'SET (redacted)' : 'NOT SET',72 clientSecret: process.env.ABRIDGE_CLIENT_SECRET ? 'SET (redacted)' : 'NOT SET',73 fhirBaseUrl: process.env.EPIC_FHIR_BASE_URL || 'NOT SET',74 timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,75 };76}7778async function testConnectivity(): Promise<Record<string, any>> {79 const results: Record<string, any> = {};80 const endpoints = [81 { name: 'abridge_api', url: `${process.env.ABRIDGE_BASE_URL}/health` },82 { name: 'fhir_server', url: `${process.env.EPIC_FHIR_BASE_URL}/metadata` },83 ];8485 for (const ep of endpoints) {86 try {87 const start = Date.now();88 const res = await fetch(ep.url, { signal: AbortSignal.timeout(5000) });89 results[ep.name] = { status: res.status, latency_ms: Date.now() - start };90 } catch (err) {91 results[ep.name] = { status: 'UNREACHABLE', error: (err as Error).message };92 }93 }94 return results;95}9697function redactPhi(text: string): string {98 return text99 .replace(/\b\d{3}-\d{2}-\d{4}\b/g, '[SSN-REDACTED]')100 .replace(/\b\d{10}\b/g, '[MRN-REDACTED]')101 .replace(/"(name|patient_name|given|family)":\s*"[^"]+"/g, '"$1": "[REDACTED]"')102 .replace(/\b\d{1,2}\/\d{1,2}\/\d{2,4}\b/g, '[DOB-REDACTED]');103}104```105106### Step 2: Session-Level Diagnostics107108```typescript109async function collectSessionDiagnostics(): Promise<any[]> {110 const api = AbridgeApiClient.getInstance().http;111 try {112 const { data } = await api.get('/encounters/sessions', {113 params: { status: 'error', limit: 10, order: 'desc' },114 });115 return data.sessions.map((s: any) => ({116 session_id: s.session_id,117 status: s.status,118 error_code: s.error_code,119 specialty: s.specialty,120 created_at: s.created_at,121 segment_count: s.segment_count,122 // No PHI fields included123 }));124 } catch {125 return [{ error: 'Could not fetch session diagnostics' }];126 }127}128```129130### Step 3: Bash Quick Diagnostic131132```bash133#!/bin/bash134# scripts/abridge-quick-diag.sh135136echo "=== Abridge Quick Diagnostics $(date -Iseconds) ==="137138echo -e "\n--- Environment ---"139echo "ABRIDGE_BASE_URL: ${ABRIDGE_BASE_URL:-NOT SET}"140echo "ABRIDGE_ORG_ID: ${ABRIDGE_ORG_ID:+SET (redacted)}"141echo "ABRIDGE_CLIENT_SECRET: ${ABRIDGE_CLIENT_SECRET:+SET (redacted)}"142143echo -e "\n--- Connectivity ---"144echo -n "API Health: "145curl -s -o /dev/null -w "%{http_code} (%{time_total}s)" \146 -H "Authorization: Bearer $ABRIDGE_CLIENT_SECRET" \147 -H "X-Org-Id: $ABRIDGE_ORG_ID" \148 "$ABRIDGE_BASE_URL/health"149150echo -e "\n\n--- TLS Info ---"151echo | openssl s_client -connect "$(echo $ABRIDGE_BASE_URL | sed 's|https://||'):443" 2>/dev/null \152 | openssl x509 -noout -subject -dates 2>/dev/null153154echo -e "\n--- DNS Resolution ---"155dig +short "$(echo $ABRIDGE_BASE_URL | sed 's|https://||')" 2>/dev/null || echo "dig not available"156157echo -e "\n=== Diagnostics Complete ==="158```159160## Output161162- `abridge-debug-{timestamp}.json` file with all PHI redacted163- Environment configuration status164- Connectivity test results with latency165- Recent error sessions (metadata only, no PHI)166167## Error Handling168169| Issue | Cause | Solution |170|-------|-------|----------|171| Bundle contains PHI | Redaction regex missed a pattern | Add pattern to `redactPhi()` function |172| Cannot reach API | Network/firewall issue | Check DNS, TLS cert, firewall rules |173| Empty error list | No recent errors | Good sign — check if issue is client-side |174175## Resources176177- [Abridge Support](https://support.abridge.com)178- [HIPAA Minimum Necessary Rule](https://www.hhs.gov/hipaa/for-professionals/privacy/guidance/minimum-necessary-requirement/)179180## Next Steps181182For rate limiting patterns, see `abridge-rate-limits`.183