# Agent Contract — TimeSafari Logging (Unified, MANDATORY)

**Author**: Matthew Raymer
**Date**: 2025-08-19
**Status**: 🎯 **ACTIVE** - Mandatory logging standards

## Overview

This document defines unified logging standards for the TimeSafari project,
ensuring consistent, rest-parameter logging style using the project logger.
No `console.*` methods are allowed in production code.

## Scope and Goals

**Scope**: Applies to all diffs and generated code in this workspace unless
explicitly exempted below.

**Goal**: One consistent, rest-parameter logging style using the project
logger; no `console.*` in production code.

## Non‑Negotiables (DO THIS)

- You **MUST** use the project logger; **DO NOT** use any `console.*`
  methods.
- Import exactly as:
  - `import { logger } from '@/utils/logger'`
  - If `@` alias is unavailable, compute the correct relative path (do not
    fail).
- Call signatures use **rest parameters**: `logger.info(message, ...args)`
- Prefer primitives/IDs and small objects in `...args`; **never build a
  throwaway object** just to "wrap context".
- Production defaults: Web = `warn+`, Electron = `error`, Dev/Capacitor =
  `info+` (override via `VITE_LOG_LEVEL`).
- **Database persistence**: `info|warn|error` are persisted; `debug` is not.
  Use `logger.toDb(msg, level?)` for DB-only.

## Available Logger API (Authoritative)

- `logger.debug(message, ...args)` — verbose internals, timings, input/output
  shapes
- `logger.log(message, ...args)` — synonym of `info` for general info
- `logger.info(message, ...args)` — lifecycle, state changes, success paths
- `logger.warn(message, ...args)` — recoverable issues, retries, degraded mode
- `logger.error(message, ...args)` — failures, thrown exceptions, aborts
- `logger.toDb(message, level?)` — DB-only entry (default level = `info`)
- `logger.toConsoleAndDb(message, isError)` — console + DB (use sparingly)
- `logger.withContext(componentName)` — returns a scoped logger

## Level Guidelines (Use These Heuristics)

### DEBUG

Use for method entry/exit, computed values, filters, loops, retries, and
external call payload sizes.

```typescript
logger.debug('[HomeView] reloadFeedOnChange() called');
logger.debug('[HomeView] Current filter settings', 
  settings.filterFeedByVisible, 
  settings.filterFeedByNearby, 
  settings.searchBoxes?.length ?? 0);
logger.debug('[FeedFilters] Toggling nearby filter', 
  this.isNearby, this.settingChanged, this.activeDid);
```

**Avoid**: Vague messages (`'Processing data'`).

### INFO

Use for user-visible lifecycle and completed operations.

```typescript
logger.info('[StartView] Component mounted', process.env.VITE_PLATFORM);
logger.info('[StartView] User selected new seed generation');
logger.info('[SearchAreaView] Search box stored', 
  searchBox.name, searchBox.bbox);
logger.info('[ContactQRScanShowView] Contact registration OK', 
  contact.did);
```

**Avoid**: Diagnostic details that belong in `debug`.

### WARN

Use for recoverable issues, fallbacks, unexpected-but-handled conditions.

```typescript
logger.warn('[ContactQRScanShowView] Invalid scan result – no value', 
  resultType);
logger.warn('[ContactQRScanShowView] Invalid QR format – no JWT in URL');
logger.warn('[ContactQRScanShowView] JWT missing "own" field');
```

**Avoid**: Hard failures (those are `error`).

### ERROR

Use for unrecoverable failures, data integrity issues, and thrown
exceptions.

```typescript
logger.error('[HomeView Settings] initializeIdentity() failed', err);
logger.error('[StartView] Failed to load initialization data', error);
logger.error('[ContactQRScanShowView] Error processing contact QR', 
  error, rawValue);
```

**Avoid**: Expected user cancels (use `info`/`debug`).

## Context Hygiene (Consistent, Minimal, Helpful)

- **Component context**: Prefer scoped logger.

```typescript
const log = logger.withContext('UserService');
log.info('User created', userId);
log.error('Failed to create user', error);
```

If not using `withContext`, prefix message with `[ComponentName]`.

- **Emojis**: Optional and minimal for visual scanning. Recommended set:
  - Start/finish: 🚀 / ✅
  - Retry/loop: 🔄
  - External call: 📡
  - Data/metrics: 📊
  - Inspection: 🔍

- **Sensitive data**: Never log secrets (tokens, keys, passwords) or
  payloads >10KB. Prefer IDs over objects; redact/hash when needed.

## Migration — Auto‑Rewrites (Apply Every Time)

- Exact transforms:
  - `console.debug(...)` → `logger.debug(...)`
  - `console.log(...)` → `logger.log(...)` (or `logger.info(...)` when
    clearly stateful)
  - `console.info(...)` → `logger.info(...)`
  - `console.warn(...)` → `logger.warn(...)`
  - `console.error(...)` → `logger.error(...)`

- Multi-arg handling:
  - First arg becomes `message` (stringify safely if non-string).
  - Remaining args map 1:1 to `...args`:
    `console.info(msg, a, b)` → `logger.info(String(msg), a, b)`

- Sole `Error`:
  - `console.error(err)` → `logger.error(err.message, err)`

- **Object-wrapping cleanup**: Replace `{{ userId, meta }}` wrappers with
  separate args:
  `logger.info('User signed in', userId, meta)`

## DB Logging Rules

- `debug` **never** persists automatically.
- `info|warn|error` persist automatically.
- For DB-only events (no console), call `logger.toDb('Message',
  'info'|'warn'|'error')`.

## Exceptions (Tightly Scoped)

Allowed paths (still prefer logger):

- `**/*.test.*`, `**/*.spec.*`
- `scripts/dev/**`, `scripts/migrate/**`

To intentionally keep `console.*`, add a pragma on the previous line:

```typescript
// cursor:allow-console reason="short justification"
console.log('temporary output');
```

Without the pragma, rewrite to `logger.*`.

## CI & Diff Enforcement

- Do not introduce `console.*` anywhere outside allowed, pragma'd spots.
- If an import is missing, insert it and resolve alias/relative path
  correctly.
- Enforce rest-parameter call shape in reviews; replace object-wrapped
  context.
- Ensure environment log level rules remain intact (`VITE_LOG_LEVEL`
  respected).

## Quick Before/After

### **Before**

```typescript
console.log('User signed in', user.id, meta);
console.error('Failed to update profile', err);
console.info('Filter toggled', this.hasVisibleDid);
```

### **After**

```typescript
import { logger } from '@/utils/logger';

logger.info('User signed in', user.id, meta);
logger.error('Failed to update profile', err);
logger.debug('[FeedFilters] Filter toggled', this.hasVisibleDid);
```

## Checklist (for every PR)

- [ ] No `console.*` (or properly pragma'd in the allowed locations)
- [ ] Correct import path for `logger`
- [ ] Rest-parameter call shape (`message, ...args`)
- [ ] Right level chosen (debug/info/warn/error)
- [ ] No secrets / oversized payloads / throwaway context objects
- [ ] Component context provided (scoped logger or `[Component]` prefix)

---

**Status**: Active and enforced
**Priority**: Critical
**Estimated Effort**: Ongoing reference
**Dependencies**: TimeSafari logger utility
**Stakeholders**: Development team, Code review team
