cc3071297b
- export_step_to_usd.py: accept --material_map CLI arg, write
schaeffler:canonicalMaterialName as customData on each Mesh prim,
fix geometry transform (strip shape Location before face exploration,
apply both face_loc and shape_loc sequentially)
- import_usd.py: after Blender USD import, use pxr to read customData
directly from the USD file — builds {part_key: material_name} lookup
(Blender ignores STRING primvars and customData, but pxr reads both)
- _blender_materials.py: add apply_material_library_direct() for exact
dict-based material assignment without name-matching heuristics
- _blender_scene_setup.py: prefer direct USD lookup, fall back to
name-matching for legacy USD files without material metadata
- export_glb.py (generate_usd_master_task): resolve material_map via
material_service.resolve_material_map() and pass to subprocess;
include material hash in cache key for invalidation
- ROADMAP.md: update P5 status, add M5-M7 milestones
Tested: 3/3 parts matched (ans_lfs120), 172/175 parts matched
(F-802007.TR4-D1-H122AG). Previous: 0/25 matched.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
122 lines
5.4 KiB
Markdown
122 lines
5.4 KiB
Markdown
# 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."
|