# Plan: P2 USD Foundation — Commit & Verify ## Context All five P2 milestones are already implemented in the working tree as uncommitted changes. The task now is to apply the DB migrations, commit the work, and verify the stack runs. ### Milestone status (assessed 2026-03-12) | Milestone | Status | Key files | |---|---|---| | M1: `export_step_to_usd.py` with `schaeffler:partKey` | ✅ DONE | `render-worker/scripts/export_step_to_usd.py` (631 lines) | | M2: `usd_master` MediaAsset + migrations 060–062 + Celery task | ✅ DONE | migrations 060/061/062, `generate_usd_master_task` in `export_glb.py` | | M3: `GET /api/cad/{id}/scene-manifest` | ✅ DONE | `part_key_service.py`, `SceneManifest` schema, endpoint in `cad.py` | | M4: `PUT /api/cad/{id}/manual-material-overrides` | ✅ DONE | New endpoint pair in `cad.py`, `saveManualOverrides` in `cad.ts` | | M5: ThreeDViewer uses partKey, survives reload | ✅ DONE | `partKeyMap` in GLB extras, `effectiveMaterials` merge, server-side persistence | ## Affected Files (all uncommitted — working tree only) **Backend** - `backend/alembic/versions/060_usd_master_asset_type.py` — new migration - `backend/alembic/versions/061_material_assignment_layers.py` — new migration - `backend/alembic/versions/062_rename_tessellation_settings.py` — new migration - `backend/app/domains/media/models.py` — `MediaAssetType.usd_master` added - `backend/app/domains/products/models.py` — 3 new JSONB columns on `CadFile` - `backend/app/domains/products/schemas.py` — `SceneManifest`, `PartEntry` Pydantic models - `backend/app/domains/pipeline/tasks/export_glb.py` — `generate_usd_master_task` + auto-chain - `backend/app/domains/pipeline/tasks/extract_metadata.py` — minor update - `backend/app/domains/pipeline/tasks/render_thumbnail.py` — minor update - `backend/app/domains/pipeline/tasks/render_order_line.py` — minor update - `backend/app/api/routers/cad.py` — scene-manifest + manual-material-overrides endpoints - `backend/app/api/routers/admin.py` — generate-missing-usd-masters + generate-missing-canonical-scenes buttons - `backend/app/services/part_key_service.py` — new file: `build_scene_manifest()`, `generate_part_key()` - `backend/app/core/config_service.py` — minor update - `backend/app/core/tenant_context.py` — new file - `backend/app/tasks/step_tasks.py` — re-exports `generate_usd_master_task` **Render worker** - `render-worker/scripts/export_step_to_usd.py` — new file: full USD exporter - `render-worker/scripts/export_step_to_gltf.py` — injects `partKeyMap` into GLB extras - `render-worker/scripts/still_render.py` — USD path support - `render-worker/scripts/turntable_render.py` — USD path support - `render-worker/Dockerfile` — `usd-core>=24.11` added **Frontend** - `frontend/src/api/cad.ts` — `getManualOverrides()`, `saveManualOverrides()` - `frontend/src/api/media.ts` — `usd_master` type added - `frontend/src/api/sceneManifest.ts` — new file: `SceneManifest`, `fetchSceneManifest()` - `frontend/src/components/cad/ThreeDViewer.tsx` — `partKeyMap`, `effectiveMaterials`, reconciliation panel - `frontend/src/components/cad/MaterialPanel.tsx` — dual-path save, provenance badge - `frontend/src/pages/Admin.tsx` — USD master bulk action buttons - `frontend/src/pages/ProductDetail.tsx` — `usd_master` row in asset table - `frontend/src/pages/Orders.tsx` — minor update ## Tasks (in order) ### [ ] Task 1: Apply migrations 060–062 - **What**: Run `docker compose exec backend alembic upgrade head` to apply the three pending migrations - **Acceptance gate**: `docker compose exec backend alembic current` shows `062` (or higher) as current - **Dependencies**: none - **Risk**: Low — each migration is additive (ADD VALUE, ADD COLUMN, UPDATE). Check for phantom drops before running. ### [ ] Task 2: TypeScript check - **What**: Run `docker compose exec frontend npx tsc --noEmit` to verify no type errors in the frontend changes - **Acceptance gate**: Zero TypeScript errors - **Dependencies**: none (frontend hot-reload, no rebuild needed) - **Risk**: Low ### [ ] Task 3: Rebuild and restart backend + render-worker - **What**: `docker compose up -d --build backend worker render-worker beat` — picks up new Dockerfile (usd-core), new tasks, and new migrations - **Acceptance gate**: `docker compose logs backend | grep "Application startup complete"` and `docker compose exec render-worker python3 -c "from pxr import Usd; print(Usd.GetVersion())"` both succeed - **Dependencies**: Task 1 - **Risk**: Medium — `usd-core` pip install adds build time; if it fails the render-worker won't start ### [ ] Task 4: Commit all P2 work - **What**: Stage and commit all uncommitted P2 files in a single `feat(P2)` commit - **Acceptance gate**: `git status` shows clean working tree (except LEARNINGS.md and review-report.md which can be included) - **Dependencies**: Tasks 1–3 (verify before committing) - **Risk**: Low ### [ ] Task 5: Smoke-test end-to-end via Admin panel - **What**: Via Admin → "Generate Missing Canonical Scenes" to regenerate GLBs with `partKeyMap` + auto-chain USD masters for existing CAD files - **Acceptance gate**: - `GET /api/cad/{id}/scene-manifest` returns `{"parts": [...], ...}` for a processed CadFile - ThreeDViewer loads, click a part → MaterialPanel shows assignment provenance - Assign a material → reload page → assignment still present - **Dependencies**: Task 3 - **Risk**: Medium — existing CAD files need backfill; may take minutes for bulk jobs to complete ## Migration Check Three migrations are pending in the working tree: - `060_usd_master_asset_type.py` — additive enum value - `061_material_assignment_layers.py` — additive JSONB columns - `062_rename_tessellation_settings.py` — UPDATE on `system_settings` rows (already checked: migration 062 was applied per review-report) **Before running**: read each migration file to confirm no unexpected DROP statements. ## Order Recommendation Migrations → TypeScript check → Rebuild → Commit → Smoke test ## Risks / Open Questions - `usd-core` build in Docker may be slow (first build) — expected, not a problem - Migration 062 may already be applied (review noted "verified by 0-row SELECT") — `alembic upgrade head` is idempotent if so - Existing CAD files need backfill for `partKeyMap` in GLB extras — handled by "Generate Missing Canonical Scenes" bulk action - `resolvePartKey()` falls back to identity (raw mesh name) for GLBs generated before this change — graceful degradation, not a blocking issue