---
id: S03
parent: M001
milestone: M001
provides:
  - Preset system with 5 tuned configs and merge-based param resolution
  - GET /engine/presets endpoint
  - Docker image kerf-engine:dev with healthcheck
  - GET /engine/health endpoint
requires:
  - slice: S02
    provides: Post-processing pipeline and output format generators (SVG, DXF, JSON) consumed by preset-driven trace flow
affects:
  []
key_files:
  - engine/presets/sign.json
  - engine/presets/patch.json
  - engine/presets/stencil.json
  - engine/presets/detailed.json
  - engine/presets/custom.json
  - engine/presets/loader.py
  - engine/api/routes.py
  - engine/tests/test_presets.py
  - docker/Dockerfile.engine
  - .dockerignore
key_decisions:
  - Preset default is 'sign' — covers the most common use case
  - Presets use flat JSON with three sections (preprocessing, vectorization, postprocessing)
  - resolve_params merges preset → user_params with user taking precedence
  - Custom preset has empty param sections so pipeline defaults apply unless user provides overrides
  - Multi-stage Docker build separates build deps from runtime (smaller image, no compiler tools)
  - Engine image contains only engine source — enforces Engine/App separation (D001)
  - Health endpoint at /engine/health for namespace consistency with other /engine/* routes
patterns_established:
  - Preset-driven pipeline configuration: presets define defaults, user params override
  - Multi-stage Docker build pattern for Python+C extension packages (pypotrace)
  - Dual health endpoints: /health (root) for simple checks, /engine/health (namespaced) for Docker/orchestration
observability_surfaces:
  - GET /engine/health — container health probe endpoint
  - GET /engine/presets — returns all available presets with full config (useful for debugging preset state)
  - Docker HEALTHCHECK — automatic container health monitoring (15s interval, 3 retries)
drill_down_paths:
  - .gsd/milestones/M001/slices/S03/tasks/T01-SUMMARY.md
  - .gsd/milestones/M001/slices/S03/tasks/T02-SUMMARY.md
duration: ""
verification_result: passed
completed_at: 2026-03-26T04:52:09.425Z
blocker_discovered: false
---

# S03: Preset System + Engine Docker Packaging

**Shipped 5 pipeline presets (sign, patch, stencil, detailed, custom) with merge-based param resolution, GET /engine/presets endpoint, and a multi-stage Docker image with healthcheck that runs the engine standalone.**

## What Happened

This slice wrapped up the M001 engine milestone with two deliverables: a preset system and Docker packaging.

**T01 — Preset System:** Created engine/presets/ package with 5 JSON config files, each tuned for a distinct vectorization use case: sign (aggressive simplification for signage), patch (smooth curves with auto-close for embroidery patches), stencil (heavy simplification with fixed threshold), detailed (max fidelity for illustrations), and custom (empty defaults — all params from user). Built loader.py with in-memory caching and resolve_params() that merges preset defaults with user-supplied overrides (user wins on conflicts). Mode now comes from the preset unless the user explicitly overrides it. Added GET /engine/presets endpoint that returns all available presets with their full config. Wired preset selection into the /engine/trace pipeline so posting with `preset: "stencil"` applies that preset's params. Postprocessing params (close_tolerance, auto_close) are now also preset-driven. 28 preset-specific tests validate loader logic, param resolution, endpoint response shape, per-preset integration, and cross-preset output differentiation.

**T02 — Docker Packaging:** Created docker/Dockerfile.engine as a two-stage build. Builder stage installs build-essential, libagg-dev, libpotrace-dev to compile pypotrace, installs all Python deps into /opt/venv. Runtime stage uses python:3.11-slim with only runtime libs (libpotrace0, libagg2, curl), copies the venv and only engine source — no App code. Added GET /engine/health returning {"status":"ok"} on the router for namespace consistency. Docker HEALTHCHECK instruction pings /engine/health (15s interval, 5s timeout, 10s start-period, 3 retries). Container builds cleanly, starts, reports healthy, and serves all engine endpoints.

## Verification

All 196 tests pass (28 preset-specific). Docker image builds from project root with `docker build -f docker/Dockerfile.engine -t kerf-engine:dev .` (exit 0). Container starts on port 8100, /engine/health returns {"status":"ok"}, Docker health status shows "healthy" with 0 failing streak, /engine/presets returns all 5 presets with full config. Container contains only engine source — no App files.

## Requirements Advanced

None.

## Requirements Validated

None.

## New Requirements Surfaced

None.

## Requirements Invalidated or Re-scoped

None.

## Deviations

T02 verification command in the plan used `cd /vmPool/r/repos/xpltdco/kerf` which doesn't exist — the correct build context is the project root at `/home/aux/development/xpltdco/kerf-engine`. T01 added auto_close and close_tolerance postprocessing params to the preset-driven trace flow (already supported by postprocess_svg but not previously exposed through the API). T02 added /engine/health alongside the existing /health root endpoint for namespace consistency.

## Known Limitations

Preset files are baked into the Docker image at build time — adding/editing presets requires a rebuild. No runtime preset hot-reload. Custom preset has empty param sections which means pipeline code defaults apply — these defaults aren't documented in the preset file itself.

## Follow-ups

Consider adding preset validation on load (schema check). Consider documenting pipeline defaults in the custom preset for discoverability. Future M002/M003 work will consume the engine container as a service.

## Files Created/Modified

- `engine/presets/sign.json` — Sign preset — aggressive simplification for signage vectorization
- `engine/presets/patch.json` — Patch preset — smooth curves with auto-close for embroidery
- `engine/presets/stencil.json` — Stencil preset — heavy simplification with fixed threshold
- `engine/presets/detailed.json` — Detailed preset — max fidelity for illustrations
- `engine/presets/custom.json` — Custom preset — empty defaults, user controls everything
- `engine/presets/loader.py` — Preset loader with caching, listing, and param merge resolution
- `engine/api/routes.py` — Added GET /engine/presets, GET /engine/health, wired preset into /engine/trace
- `engine/tests/test_presets.py` — 28 tests covering loader, resolution, endpoint, integration, cross-preset differentiation
- `docker/Dockerfile.engine` — Multi-stage Dockerfile: builder compiles pypotrace, runtime uses slim image with engine source only
- `.dockerignore` — Excludes .git, .venv, __pycache__, .gsd, node_modules from Docker build context
