# Decisions Register

<!-- Append-only. Never edit or remove existing rows.
     To reverse a decision, add a new row that supersedes it.
     Read this file at the start of any planning or research phase. -->

| # | When | Scope | Decision | Choice | Rationale | Revisable? | Made By |
|---|------|-------|----------|--------|-----------|------------|---------|
| D001 |  | architecture | Engine/App architectural relationship | Engine is standalone module, App is a consumer. Zero coupling — App calls Engine only via HTTP API. | Engine is proprietary IP that must be embeddable into future applications independently. Clean input/output contracts enable this. | No | human |
| D002 |  | architecture | Build order and gating strategy | Build Engine first (M001), then App canvas (M002), then Export+Deploy+Embed (M003). Human checkpoints gate each transition. | Brief explicitly mandates: validate engine output quality before building canvas UI, validate canvas before export/deploy. Engine is the hardest and most valuable piece. | No | human |
| D003 |  | engine | Post-processing replaces regex metadata extraction | postprocess_svg() pipeline replaces old _extract_svg_metadata() regex approach; all SVG paths are parsed into structured PathInfo objects with coordinates, area, island status | Structured path data is needed for DXF/JSON output generation, RDP simplification, and island detection. XML parsing is now necessary since we need actual coordinate data, not just counts. This supersedes D003's regex approach. | No | agent |
| D004 |  | architecture | Engine Docker image build strategy | Multi-stage build: builder stage compiles pypotrace with build-essential/libagg-dev/libpotrace-dev, runtime stage uses python:3.11-slim with only runtime libs (libpotrace0, libagg2, curl). Only engine source is copied — no App code. | Multi-stage keeps the runtime image small by excluding build tools. Copying only engine source enforces the Engine/App separation (D001). curl is included for Docker HEALTHCHECK. | Yes | agent |
| D005 |  | architecture | Frontend technology stack for Kerf App | Vite + React + TypeScript with plain CSS modules, Vitest for testing, raw fetch + FormData for engine API calls, no UI framework for V1 | Minimal dependency surface for a tool that needs fast iteration. The engine API uses multipart/form-data which works naturally with native fetch + FormData. CSS modules avoid global style conflicts without adding a framework. Vitest integrates natively with Vite's transform pipeline. No UI library needed — the app has a focused interface with ~8 components. | Yes | agent |
| D006 |  | frontend | React hook params stabilization strategy for useDebouncedTrace | JSON.stringify params in useEffect deps array, single-effect architecture | useCallback-based triggerTrace with object params caused infinite re-render loops because React creates new object references each render. JSON.stringify converts params to a stable string for dependency comparison, eliminating the need for callers to useMemo their params objects. Simpler API surface and no re-render bugs. | Yes | agent |
| D007 |  | architecture | Canvas object type system design | Discriminated union on `type` field: 'rect' \| 'circle' \| 'ellipse' \| 'line' \| 'image'. All objects share BaseCanvasObject (id, name, x, y, visible, locked, stroke, fill, opacity). Type-specific fields via intersection types. | TypeScript discriminated unions enable exhaustive type narrowing in switch/if statements, catching missing cases at compile time. Shared base keeps CRUD operations generic while type-specific panels (ShapeProperties) safely narrow to access unique fields. 'text' type will be added in S03. | Yes | agent |
