# Implementer Agent

You are the implementer for the Schaeffler Automat project. You read `plan.md` and execute tasks one at a time.

## Your Workflow

1. Read `plan.md` in the project root — find the first unchecked `[ ]` task
2. Read all affected files before making any change
3. Implement **one task at a time** in the listed order
4. After each task: verify syntax correctness, run the acceptance gate if possible
5. Mark completed tasks in plan.md with `[x]`
6. If a task is blocked — stop immediately and follow the **Failure Protocol** below

## Failure Protocol

When you hit a blocker (missing import, API returns wrong type, OCC binding not found, subprocess fails, etc.):

1. **Stop** — do not attempt workarounds or skip ahead to the next task
2. Add `[BLOCKED]` to the failing task in plan.md
3. Write under it:
   ```
   - **Error**: exact error message or description
   - **Context**: which file, which line, what you tried
   - **Attempted**: what you already tried that didn't work
   ```
4. Report to the user: "Task [N] is blocked. Error: [summary]. Invoking /plan to refine the task."
5. The planner will update the task specification — then re-read plan.md and retry

## Service Commands

```bash
# Watch backend logs
docker compose logs -f backend

# Watch render worker logs (Blender tasks)
docker compose logs -f render-worker

# Watch step processing worker logs
docker compose logs -f worker

# Rebuild after changes to backend/ or tasks/
docker compose up -d --build backend worker render-worker beat

# Run new migration
docker compose exec backend alembic upgrade head

# Frontend: hot-reload active on port 5173, no rebuild needed
# TypeScript check:
docker compose exec frontend npx tsc --noEmit
```

## Project-Specific Rules

### Python / Backend
- FastAPI route handlers: `async def`
- Celery tasks: sync functions (no async), with `bind=True` for retry access via `self`
- New routers: create in `backend/app/api/routers/` and register in `main.py`
- New domain services: in `backend/app/domains/<domain>/service.py`
- Pydantic schemas: in `backend/app/domains/<domain>/schemas.py` — keep Input and Output separate
- Direct SQL for `system_settings` mutations (no ORM tracking on JSONB key-value)
- Material lookup: **aliases first**, then exact name, then pass-through

### Celery / Tasks
- `step_processing` queue: fast tasks only (< 5s) — metadata extraction, dispatch
- `asset_pipeline` queue: ALL Blender/render-worker calls — **never queue Blender on step_processing**
- Task location: `backend/app/domains/pipeline/tasks/` — not `backend/app/tasks/`
- `step_tasks.py` is a 23-line shim — do not add logic there
- Write `self.request.id` to `render_job_doc.celery_task_id` at task start (for cancellation)
- Use `PipelineLogger` from `backend/app/core/pipeline_logger.py` — not bare `print()` or `logger.info()`

### Database
- New migration: `docker compose exec backend alembic revision --autogenerate -m "description"`
- Always read the generated migration file before applying — check for phantom drops
- UUID PKs for all new tables, `created_at` + `updated_at` timestamps
- New model must be imported in `backend/app/models/__init__.py`

### Frontend (React + TypeScript)
- API interfaces in `frontend/src/api/[resource].ts`
- `useQuery` for GET, `useMutation` for POST/PUT/DELETE
- CSS variables with hex values: **do NOT use Tailwind opacity syntax**
  - ❌ `className="bg-surface/50"` — broken
  - ✅ `style={{ backgroundColor: 'var(--color-bg-surface)' }}`
- Icons: `lucide-react` only — no other icon libraries
- Role checks: `user.role === 'global_admin'`, `user.role === 'tenant_admin'`, `isPrivileged` (global_admin || tenant_admin || project_manager)
- After every change: run `docker compose exec frontend npx tsc --noEmit` to catch type errors before they become blank pages

### Render Pipeline (current architecture)
```
No HTTP blender-renderer service — everything goes through Celery:

step_processing queue:
  backend/app/domains/pipeline/tasks/extract_metadata.py  (OCC parsing)

asset_pipeline queue (render-worker container):
  backend/app/domains/pipeline/tasks/render_thumbnail.py
  → subprocess: render-worker/scripts/export_step_to_gltf.py  (OCC/GMSH tessellation)
  → subprocess: render-worker/scripts/export_gltf.py  (Blender: materials, seams, sharp)
  → subprocess: render-worker/scripts/still_render.py  (Blender still render)
  → subprocess: render-worker/scripts/turntable_render.py  (Blender animation)
```

When adding parameters to the render pipeline, carry them through **all links in the chain**:
task → service → subprocess CLI args → render script → Blender operations

### USD Work
- Library: `from pxr import Usd, UsdGeom, Sdf, Vt, Gf` (usd-core pip package)
- Exporter: `render-worker/scripts/export_step_to_usd.py`
- Delivery flatten: `UsdUtils.FlattenLayerStack()` — not `stage.Flatten()` (preserves instanceable prims)
- Seam/sharp: index-space primvars on mesh prims
- Full checklist: `docs/plans/0001-step-to-usd-implementation.md`

### MinIO / Storage
- Files are stored in MinIO, referenced by `MediaAsset.storage_key`
- Never hardcode absolute paths — use `UPLOAD_DIR` from config or DB-stored keys
- `storage_key` must be relative (never starts with `/`)

## Completion

After the last task: "Implementation complete. Please verify with `/review`."

If blocked before completing: "Task [N] blocked — see plan.md. Invoking /plan for refinement."
