---
phase: 09-timing-profiles
plan: 01
subsystem: profiles
tags: [timing-profiles, data-layer, presets, crud]
dependency_graph:
  requires: []
  provides: [TimingProfile-type, timing-crud, builtin-presets, parameter-summary]
  affects: [profile-manager, profile-types, profiles-json]
tech_stack:
  added: []
  patterns: [builtin-shadow-merge, lazy-load-map]
key_files:
  created:
    - src/profiles/timing-presets.ts
  modified:
    - src/profiles/profile-types.ts
    - src/profiles/profile-manager.ts
decisions:
  - "Timing fields all optional on TimingProfile for partial-override merge semantics (D-06)"
  - "Builtins use fixed 2026-01-01 timestamps to distinguish from user-created profiles"
  - "User profiles shadow builtins by slug; builtins cannot be deleted"
metrics:
  duration: 151s
  completed: "2026-04-13T11:15:49Z"
  tasks: 3
  files: 3
---

# Phase 9 Plan 01: Timing Profile Data Layer Summary

Timing profile type system, CRUD on ProfileManager, four built-in presets with shadow semantics, and human-readable parameter summary generator.

## Tasks Completed

| Task | Name | Commit | Files |
|------|------|--------|-------|
| 1 | Add TimingProfile type and update ProfilesFileData | f30830d | src/profiles/profile-types.ts |
| 3 | Create built-in timing presets and parameter summary generator | 48ec1f9 | src/profiles/timing-presets.ts |
| 2 | Extend ProfileManager with timing profile CRUD | e37775b | src/profiles/profile-manager.ts |

## What Was Built

- **TimingProfile interface** with 13 fields (slug, displayName, intervalMs, maxFrames, durationMs, jpegQuality, deltaHighlight, compressIdle, gifExport, description, createdAt, updatedAt, builtin). All timing/diagnostic fields optional per D-06.
- **SaveTimingProfileInput interface** for creating/updating timing profiles.
- **ProfilesFileData.timing** upgraded from `Record<string, unknown>` to `Record<string, TimingProfile>`.
- **ProfileManager timing CRUD**: saveTiming, getTiming, deleteTiming, listTiming, saveTimingFromSession -- all alongside existing screenshot profile methods.
- **BUILTIN_TIMING_PRESETS**: quick-glance (500ms/6 frames), steady-watch (2s/20 frames/40s), debug-flicker (200ms/30 frames/delta), slow-monitor (5s/50 frames/5min/idle-compressed).
- **generateParameterSummary()**: Produces one-liners like "every 500ms, max 6 frames" from any TimingProfile.

## Key Implementation Details

- Timing profiles stored in same JSON file as screenshot profiles under `timing` key
- User profiles shadow builtins with same slug (D-14); listTiming merges both sets
- deleteTiming returns `{ deleted: boolean, isBuiltin: boolean }` to distinguish "not found" from "cannot delete builtin"
- saveTimingFromSession extracts timing params from a CaptureConfig for quick profile creation
- Task execution order was 1, 3, 2 (presets file created before manager imports it)

## Deviations from Plan

None -- plan executed exactly as written.

## Self-Check: PASSED
