---
id: S01
milestone: M001
status: complete
tasks_completed: 5
tasks_total: 5
completed_at: 2026-03-26T04:30:00.000Z
---

# S01: Core Pipeline — Preprocessing + Vectorization

## Goal
Stand up FastAPI server with OpenCV preprocessing pipeline and dual-mode vectorization (Potrace + VTracer). Establish the repo structure, dependencies, and core /engine/trace endpoint.

## Outcome
All 5 tasks completed successfully. The engine accepts PNG uploads via POST /engine/trace and returns SVG output with metadata using either Potrace or VTracer mode. Full test suite: 76 tests passing.

## What Was Built

### T01: Project Scaffold
Created engine/ Python project with FastAPI skeleton, pyproject.toml, all dependencies (fastapi, uvicorn, opencv-python-headless, pypotrace, vtracer, python-multipart, Pillow). Verified uvicorn starts cleanly.

### T02: OpenCV Preprocessing Pipeline
Implemented `engine/pipeline/preprocessing.py` with full pipeline: grayscale conversion, bilateral filter denoise, CLAHE contrast enhancement, Otsu thresholding, optional Canny edge detection, morphological operations. All stages tunable via parameters dict.

### T03: Potrace Vectorization (Mode A)
Implemented `potrace_trace()` in `engine/pipeline/vectorize.py`. Converts preprocessed binary images to SVG via pypotrace with tunable params (turdsize, alphamax, opticurve, opttolerance).

### T04: VTracer Vectorization (Mode B)
Implemented `vtracer_trace()` in `engine/pipeline/vectorize.py`. Converts grayscale or color images to SVG via vtracer Python bindings with tunable params (colormode, filter_speckle, color_precision, etc.).

### T05: API Endpoint + Integration Tests
Created `engine/api/routes.py` with POST /engine/trace endpoint. Accepts multipart form-data (file, mode, output_format, preset, params). Returns JSON with SVG output and metadata (path_count, node_count_total, open_paths, processing_ms, warnings). 14 integration tests covering both modes, metadata shape, custom params, and validation errors.

## Key Files
- `engine/main.py` — FastAPI app entry point
- `engine/api/routes.py` — /engine/trace endpoint
- `engine/pipeline/preprocessing.py` — OpenCV preprocessing pipeline
- `engine/pipeline/vectorize.py` — Potrace + VTracer vectorization
- `engine/tests/` — 76 tests (unit + integration)

## Key Decisions
- SVG metadata extraction via regex (lightweight, no XML parser dependency)
- Vectorize params filtered by known param names per mode
- Bilateral filter chosen over Gaussian for edge-preserving denoise
- CLAHE for contrast rather than simple histogram equalization

## Verification
Full test suite: `cd engine && .venv/bin/python -m pytest tests/ -v` — 76 passed

## Demo
POST /engine/trace with a PNG logo returns valid SVG using both Potrace and VTracer modes.

## Known Limitations
- Output format is SVG-only — DXF and JSON deferred to S02
- `preset` parameter accepted but ignored — preset system deferred to S03
- No Docker packaging yet — deferred to S03
- Tests must run with `.venv/bin/python -m pytest`, not bare `python`

## Forward Intelligence

### What the next slice should know
- Response shape: `{output: str, format: str, metadata: {path_count, node_count_total, open_paths, warnings, processing_ms}}`. S02 must extend for DXF/JSON without breaking this contract.
- VTracer returns SVG with XML declaration + generator comment; Potrace's `_path_to_svg()` returns bare SVG. Post-processing must handle both.
- User params are filtered by known names per mode in routes.py lines 80-91. New params for S02 post-processing stages must be added to these filter lists.

### What's fragile
- `_extract_svg_metadata()` regex assumes `<path d="...">` — if output format changes, metadata counts silently return 0.
- pypotrace Bitmap requires uint32 data — feeding other dtypes directly will segfault (see L003 in KNOWLEDGE.md).

### Authoritative diagnostics
- `engine/.venv/bin/python -m pytest tests/ -v` — full pipeline health check, runs in <1s.
- `GET /health` returns `{"status": "ok"}` — confirms FastAPI is running.

### What assumptions changed
- VTracer Python bindings work via `convert_raw_image_to_svg()` with PNG bytes — no subprocess needed (original plan suggested subprocess might be required).
- Test images are generated programmatically via numpy, not loaded from fixture files.
