# Phase 4 Productization - Constants Consolidation Audit

> **Generated:** 2025-12-29
> **Implemented:** 2025-12-29
> **Scope:** `src/noteflow/` (Python) + `client/` (TypeScript/Rust)
> **Status:** ✅ Consolidation Complete

## Executive Summary

This audit identifies constants scattered across the NoteFlow codebase that could be consolidated for improved maintainability, reduced duplication, and cross-platform consistency.

| Category | Python | Rust | TypeScript | Total Issues |
|----------|--------|------|------------|--------------|
| Critical Duplicates | 4 | 1 | 2 | **7** |
| Medium Priority | 6 | 2 | 5 | **13** |
| Low Priority | 5 | 3 | 4 | **12** |

**Key Findings:**
- **Duplicate File**: `client/src/api/constants.ts` duplicates `tauri-constants.ts` (delete one)
- **Cross-Platform Mismatch**: Webhook timeout defined differently in Python domain vs ORM
- **Summary Limits**: `max_key_points=5` and `max_action_items=10` duplicated in 2 Python files
- **Timing Constants**: TypeScript has no centralized timing module (Rust has excellent one)

---

## Python Backend Findings (`src/noteflow/`)

### Critical Duplicates (Immediate Action Required)

#### 1. Summary Generation Limits
| Value | Location 1 | Location 2 |
|-------|-----------|-----------|
| `max_key_points = 5` | `domain/summarization/ports.py:24` | `application/services/summarization_service.py:63` |
| `max_action_items = 10` | `domain/summarization/ports.py:25` | `application/services/summarization_service.py:64` |

**Fix:** Define in `domain/summarization/ports.py`, import in service.

#### 2. Webhook Timeout Default
| Value | Location 1 | Location 2 |
|-------|-----------|-----------|
| `timeout_ms = 10000` | `domain/webhooks/events.py:54` | `infrastructure/persistence/models/integrations/webhook.py:53` |

**Fix:** Single source in `domain/webhooks/events.py`.

#### 3. gRPC Port
| Value | Locations |
|-------|-----------|
| `50051` | `grpc/_config.py:12`, `grpc/_config.py:131`, `config/constants.py:17` |

**Fix:** Keep only in `grpc/_config.py`, remove from `config/constants.py`.

#### 4. Default List Limits
| Value | Files | Count |
|-------|-------|-------|
| `100` | `meeting_service.py`, `meeting_repo.py`, `meeting_store.py`, `memory/repositories.py` | 4+ |
| `20` | `ports/repositories/external.py`, `google_adapter.py`, `outlook_adapter.py` | 3+ |
| `50` | `ports/repositories/external.py`, `webhook_repo.py`, `memory/repositories.py` | 3+ |

**Fix:** Create `infrastructure/persistence/constants.py` with pagination defaults.

### Medium Priority

#### 5. Webhook HTTP Headers (String Literals)
```python
# infrastructure/webhooks/executor.py
"X-NoteFlow-Signature"  # line 223
"X-NoteFlow-Event"      # line 212
"X-NoteFlow-Delivery"   # line 213
"sha256="               # line 223
```

**Fix:** Create `infrastructure/webhooks/constants.py`.

#### 6. Timeout/Duration Values
| Value | Locations | Usage |
|-------|-----------|-------|
| `2.0` | `grpc/service.py:83`, `config/constants.py:27` | Partial cadence, flush interval |
| `5.0` | `grpc/_config.py:132`, `grpc/client.py:105` | Connection timeout |
| `10.0` | `webhooks/executor.py:42` | Webhook timeout fallback |
| `0.1` | `grpc/_config.py:145`, `config/constants.py:13` | Chunk timeout, position update |
| `0.5` | `asr/segmenter.py:38`, `diarization/engine.py:41`, `triggers/app_audio.py:59` | Silence, latency |

**Fix:** Group by subsystem in respective config modules.

#### 7. Audio Chunk Duration
| Value | Location 1 | Location 2 |
|-------|-----------|-----------|
| `100` ms | `infrastructure/audio/protocols.py:44` | `infrastructure/audio/capture.py:85` |

**Fix:** Consolidate in `infrastructure/audio/constants.py`.

### Already Well-Managed

- OAuth field names in `config/constants.py:52-65`
- Authorization headers in `config/constants.py:67-70`
- Error messages in `grpc/_mixins/errors.py`
- Audio sample rate in `config/constants.py:10`
- Buffer sizes in `config/constants.py:24`

---

## Client Findings (`client/`)

### Critical Issue: Duplicate Constants File

**Files:**
- `client/src/api/constants.ts` (older, incomplete)
- `client/src/api/tauri-constants.ts` (newer, complete)

**Discrepancy:**
- `tauri-constants.ts` has **46 commands**
- `constants.ts` has **~37 commands**

**Missing in `constants.ts`:**
```typescript
GRANT_CLOUD_CONSENT, REVOKE_CLOUD_CONSENT, GET_CLOUD_CONSENT_STATUS,
EXTRACT_ENTITIES, UPDATE_ENTITY, DELETE_ENTITY,
LIST_CALENDAR_EVENTS, GET_CALENDAR_PROVIDERS,
INITIATE_OAUTH, COMPLETE_OAUTH, GET_OAUTH_CONNECTION_STATUS, DISCONNECT_OAUTH,
REGISTER_WEBHOOK, LIST_WEBHOOKS, UPDATE_WEBHOOK, DELETE_WEBHOOK, GET_WEBHOOK_DELIVERIES,
START_INTEGRATION_SYNC, GET_SYNC_STATUS, LIST_SYNC_HISTORY,
GET_RECENT_LOGS, GET_PERFORMANCE_METRICS
```

**Fix:** Delete `constants.ts`, use `tauri-constants.ts` everywhere.

### TypeScript Timing Constants (Missing Module)

**Hardcoded values scattered:**
| Value (ms) | File | Line |
|-----------|------|------|
| 500 | `use-audio-devices.ts` | 352 |
| 1000 | `reconnection.ts` | 13 |
| 1200 | `use-preferences-sync.ts` | 16 |
| 2000 | `use-diarization.ts` | 38 |
| 5000 | `use-integration-sync.ts` | 294, 316 |
| 15000 | `reconnection.ts` | 14 |

**Fix:** Create `client/src/lib/timing.ts` mirroring Rust's excellent `constants.rs`.

### TypeScript Status Strings (Scattered)

| Value | Files | Count |
|-------|-------|-------|
| `'idle'` | `use-integration-sync.ts`, `use-webhooks.ts` | 2+ |
| `'syncing'` | `use-integration-sync.ts` | 1+ |
| `'success'` | `use-integration-sync.ts`, `use-webhooks.ts` | 6+ |
| `'error'` | `use-integration-sync.ts`, `use-webhooks.ts` | 5+ |
| `'calendar'` | `use-integration-sync.ts` | **5** |
| `'pkm'` | `use-integration-sync.ts` | **4** |
| `'__global__'` | `preferences.ts` | **4** |

**Fix:** Create `client/src/lib/status-constants.ts`.

### Rust Constants (Well-Organized)

`client/src-tauri/src/constants.rs` is **excellent**:

```rust
// Sections include:
pub mod grpc { ... }      // CONNECTION_TIMEOUT, REQUEST_TIMEOUT, DEFAULT_PORT
pub mod audio { ... }     // DEFAULT_SAMPLE_RATE, VU_UPDATE_RATE, MIN_DB_LEVEL
pub mod playback { ... }  // TICK_INTERVAL
pub mod recording { ... } // TIMER_INTERVAL
pub mod triggers { ... }  // DEFAULT_SNOOZE_DURATION, POLL_INTERVAL
pub mod crypto { ... }    // NONCE_SIZE, KEY_SIZE, KEYCHAIN_SERVICE
pub mod webhooks { ... }  // DEFAULT_TIMEOUT_MS, DEFAULT_MAX_RETRIES
pub mod pagination { ... }// DEFAULT_LIMIT, MAX_MEETINGS_LIMIT
```

**Status:** Model for TypeScript consolidation.

---

## Cross-Platform Alignment

### Constants That Should Match

| Constant | Python | Rust | TypeScript | Status |
|----------|--------|------|------------|--------|
| Sample Rate | `16000` | `16000` | — | Match |
| gRPC Port | `50051` | `50051` | — | Match |
| Webhook Timeout | `10000` ms | `10000` ms | — | Match |
| Max Retries | `3` | `3` | — | Match |
| Audio Flush Interval | `2.0` s | `2.0` s | — | Match |
| Default List Limit | `100` | `50` | — | **Mismatch** |
| Delivery History Limit | `50` | `50` | — | Match |

### Potential Sync Issues

1. **Keychain Service Names (Rust)**
   ```rust
   crypto::KEYCHAIN_SERVICE = "noteflow"
   secrets::KEYCHAIN_SERVICE = "com.noteflow.secrets"
   ```
   Two different values in same codebase.

2. **List Limit Default**
   - Python: `100` (meetings)
   - Rust: `50` (pagination)

   Should align on one value.

---

## Recommended Action Plan

### Phase 1: Critical (Immediate)

| Action | Files | Effort |
|--------|-------|--------|
| Delete duplicate `constants.ts` | `client/src/api/constants.ts` | Low |
| Consolidate summary limits | `domain/summarization/ports.py`, `application/services/summarization_service.py` | Low |
| Fix webhook timeout duplication | `domain/webhooks/events.py`, `persistence/models/integrations/webhook.py` | Low |
| Deduplicate gRPC port | `grpc/_config.py`, `config/constants.py` | Low |

### Phase 2: Medium Priority

| Action | New File | Affected Files |
|--------|----------|----------------|
| Create webhook headers module | `infrastructure/webhooks/constants.py` | `executor.py` |
| Create pagination defaults | `infrastructure/persistence/constants.py` | 4+ repositories |
| Create TypeScript timing module | `client/src/lib/timing.ts` | 5+ hooks |
| Create TypeScript status constants | `client/src/lib/status-constants.ts` | `use-integration-sync.ts`, `use-webhooks.ts` |

### Phase 3: Nice-to-Have

| Action | Description |
|--------|-------------|
| Consolidate timeout/duration values | Group by subsystem |
| Extract panel layout constants | From `use-panel-preferences.ts` |
| Extract reminder defaults | From `use-meeting-reminders.ts` |
| Document cross-platform constant sharing | README or architecture doc |

---

## Proposed New Files

### Python

```
src/noteflow/infrastructure/webhooks/constants.py
├── HTTP_HEADER_WEBHOOK_SIGNATURE = "X-NoteFlow-Signature"
├── HTTP_HEADER_WEBHOOK_EVENT = "X-NoteFlow-Event"
├── HTTP_HEADER_WEBHOOK_DELIVERY = "X-NoteFlow-Delivery"
├── WEBHOOK_SIGNATURE_PREFIX = "sha256="
└── DEFAULT_WEBHOOK_MAX_RESPONSE_LENGTH = 500

src/noteflow/infrastructure/persistence/constants.py
├── DEFAULT_LIST_LIMIT = 100
├── DEFAULT_CALENDAR_EVENT_LIMIT = 20
└── DEFAULT_WEBHOOK_DELIVERY_HISTORY_LIMIT = 50
```

### TypeScript

```
client/src/lib/timing.ts
├── BASE_DELAY_MS = 1000
├── MAX_DELAY_MS = 15000
├── DIARIZATION_POLL_MS = 2000
├── SYNC_POLL_MS = 500
├── SYNC_TIMEOUT_MS = 60000
├── PREFERENCES_DEBOUNCE_MS = 1200
└── DEVICE_REFRESH_MS = 500

client/src/lib/status-constants.ts
├── SyncStatus = { IDLE, SYNCING, SUCCESS, ERROR }
├── IntegrationType = { CALENDAR, PKM }
└── GLOBAL_SPEAKER_ID = '__global__'
```

---

## Files Summary

### High-Touch Files (Most Constants)

| File | Language | Constant Count |
|------|----------|----------------|
| `config/constants.py` | Python | 15+ |
| `src-tauri/src/constants.rs` | Rust | 50+ |
| `api/tauri-constants.ts` | TypeScript | 60+ |
| `config/settings.py` | Python | 20+ (defaults) |
| `use-integration-sync.ts` | TypeScript | 10+ (scattered) |

### Files to Delete

- `client/src/api/constants.ts` (duplicate of `tauri-constants.ts`)

### Files to Create

- `src/noteflow/infrastructure/webhooks/constants.py`
- `src/noteflow/infrastructure/persistence/constants.py`
- `client/src/lib/timing.ts`
- `client/src/lib/status-constants.ts`

---

## Appendix: Complete Constant Inventory

### Python `config/constants.py` (Current)

```python
DEFAULT_SAMPLE_RATE = 16000
POSITION_UPDATE_INTERVAL = 0.1
DEFAULT_GRPC_PORT = 50051
MAX_GRPC_MESSAGE_SIZE = 100 * 1024 * 1024
AUDIO_BUFFER_SIZE_BYTES = 320_000
PERIODIC_FLUSH_INTERVAL_SECONDS = 2.0
APP_DIR_NAME = ".noteflow"
DEFAULT_MEETING_TITLE = "Untitled"
OAUTH_FIELD_ACCESS_TOKEN = "access_token"
OAUTH_FIELD_REFRESH_TOKEN = "refresh_token"
OAUTH_FIELD_TOKEN_TYPE = "token_type"
OAUTH_FIELD_SCOPE = "scope"
OAUTH_FIELD_EXPIRES_IN = "expires_in"
HTTP_AUTHORIZATION = "Authorization"
HTTP_BEARER_PREFIX = "Bearer "
```

### Rust `constants.rs` Modules

```rust
grpc        // 7 constants
audio       // 11 constants
playback    // 2 constants
recording   // 2 constants
triggers    // 7 constants
crypto      // 4 constants
cache       // 5 constants
collection  // 4 constants
secrets     // 2 constants
webhooks    // 5 constants
pagination  // 3 constants
```

### TypeScript `tauri-constants.ts` Sections

```typescript
Commands    // 46 command names
Events      // 13 event names
Errors      // 6 error codes
OAuthScopes // 2 OAuth scope strings
HttpStatus  // 7 HTTP status codes
Placeholders// 1 placeholder URL
Timing      // 5 timing constants
```
