Phase 0 audit performed 2026-07-06 on the Strix Halo reference machine (Ryzen AI MAX+ 395, 128 GB, ROCm). This document is the living tracker for the 1.0 push: findings are checked off as they land.
- Read every doc (
README.md,backend/README.md,AGENTS.md,project_status_and_backlog.md), all compose files, scripts, the full frontend, and the backend config/route surface. - Ran the canonical backend test command, frontend lint + production build.
- Booted the backend against disposable Postgres/Redis containers with a CPU profile and walked the real first-run flow over HTTP: auth setup, login/session, settings/hardware/model-status, valid + invalid upload, job listing, delete.
- Not exercised live in this audit: full model pipeline on ROCm (requires multi-GB model downloads; validated separately per the acceptance log), NVIDIA and Apple paths (no such hardware attached — status taken from the repo's own live-validation log and marked accordingly below).
| Check | Result |
|---|---|
uv run pytest backend/tests (canonical command) |
FAILS collection on the reference machine (see F1) |
HARDWARE_PROFILE=cpu_only GPU_BACKEND=cpu uv run pytest backend/tests |
197 passed, 2 failed (F2, F3) |
npm run lint (frontend) |
clean |
npm run build (frontend) |
clean |
| First-run auth → upload → jobs → delete via HTTP | works |
| Invalid upload rejection (non-video file) | works |
- F1. Test suite cannot run on the reference machine.
get_settings()probes real hardware at import time andvalidate_hardware_requirementsraises when Strix Halo is detected without ROCm torch (backend/app/config.py:599,:214-225), souv run pytest backend/testsdies with 15 collection errors on the very machine AGENTS.md names as the review surface. Tests must pin a hardware profile (conftest env override) so the suite is deterministic everywhere. - F2. Author-machine path baked into a test.
backend/tests/test_config.py:283asserted a developer-specific upload path; fixed to assert relative to the detected project root. - F3. HEAD committed with a red test.
backend/tests/test_nvidia_runtime_contract.py:10still expects the vLLMv0.11.2image;docker-compose.nvidia.ymlwas bumped tov0.17.1inc82d8a1without updating the contract test. - F4. Dead script reference.
scripts/setup.shno longer references the removed./scripts/download-models.sh; setup now points users to Settings → Model Downloads or first-processing auto-downloads whenMODEL_AUTO_DOWNLOAD=true, and prints health/readiness self-checks. - F5. Dependency locking added.
frontend/package-lock.jsonandbackend/uv.lockare present, Dockerfiles install from those locks (npm ci/ frozenuv export),llama-cpp-pythonis pinned tov0.3.33, and the externalllama.cppbuild default is pinned tob9888. Optional NeMo git installation remains intentionally unchanged. - F6. No CI. GitHub Actions now runs backend tests, a scoped backend ruff gate, frontend lint/typecheck/build, frontend Docker build smoke, and compose config validation on push and pull requests to
main. - F7.
.gitignoremissesnode_modules/and.next/, so a local frontend install dirties the tree.
- F8. Batch API is invisible.
/api/batch(create/list/get/cancel —backend/app/api/routes/batch.py) has zero callers infrontend/lib/api.ts. The upload modal loops single uploads and its copy claims sequential processing. AGENTS.md names batch as a drift hotspot; the UI side simply doesn't exist. - F9. Similar-videos feature is invisible.
/api/search/similar/{video_id}is implemented and rerank-tuned, but no UI surface ever calls it. - F10. No job cancel/retry from the UI.
/api/jobs/{id}/canceland/retryexist; the frontend only exposes video-level retry/reset on cards. A stuck processing job cannot be cancelled from the product. - F11. Job WebSocket unused. Resolved by decision: the redesigned UI keeps interval polling as the single tested mechanism for 1.0; the WebSocket route remains available for automation and is documented in docs/ARCHITECTURE.md. Re-evaluate post-1.0.
- F12. Slides can never show images. Summary responses expose only slide filenames and the backend now serves stored slide images, and the Slides tab now renders the images with fallbacks.
- Backend:
GET /api/summaries/{video_id}/slides/{filename}serves only slide images stored on that exact video, with separator rejection and 404s for unknown images.
- Backend:
- F13. Native dialogs.
window.alert/window.confirmatfrontend/app/page.tsx:156,164,246,frontend/app/videos/[id]/page.tsx:144,frontend/components/video-card.tsx:118. - F14. Swallowed errors. Search/ask mutation errors never render (
frontend/app/search/page.tsx); delete/tag failures go toconsole.error(frontend/app/videos/[id]/page.tsx:154,168); a failed file inuploadAllsilently aborts the rest (frontend/components/upload-dropzone.tsx:37-42) with no visible error anywhere. - F15. Cryptic status UI. Single-letter model chips (T/D/V/S/E) with hover-only disclosure (
frontend/app/page.tsx:69-75,264-319); raw status strings; tooltips unreachable by keyboard/touch. - F16. Labels are blind typing. The backend now lists existing labels, and video detail, search, and todos now use the TagInput suggestion component fed by that endpoint.
- Backend:
GET /api/videos/labelsreturns distinct user labels with per-label video counts for UI suggestions.
- Backend:
- F17. No responsive layout. Fixed 256 px always-dark sidebar (
frontend/components/sidebar.tsx:41), no mobile navigation; main layout assumes desktop. - F18. Dark-mode flash. Theme class applied in a post-mount effect (
frontend/components/theme-toggle.tsx), no pre-hydration script;<html>ships light. - F19. Upload UX gaps. No per-file progress (plain
fetch), size limit and accepted-format constraints not communicated before failure. - F20. First-run model experience violates the consent rule. Fresh install shows all models
uncachedwith no guided UI download; the worker can auto-download multi-tens-of-GB GGUFs on first job unlessMODEL_AUTO_DOWNLOAD=false. Backend progress:/api/settings/models/recommendationsnow returns profile-aware recommendations,/api/settings/models/downloadstarts explicit consent-based downloads with progress/disk checks and HF-token/license guidance, and workers/managed endpoints can fail closed when auto-download is disabled. The Settings download manager now provides the consent-based UI on top of these endpoints. - F21. Duplicate detection is invisible.
videos.duplicate_infois written, search suppression works, and video APIs expose safe duplicate metadata, and the UI now shows duplicate badges on cards plus a banner with score and representative link on the detail page.- Backend: video list/detail responses expose a sanitized
duplicate_infosubset without filesystem paths.
- Backend: video list/detail responses expose a sanitized
- F22. "Work in Progress" banner removed once F1–F21 and the launch checklist held (see the 1.0 readiness report).
- F23. Private identifiers throughout. Internal IPs, hostnames, and user paths across
README.md,backend/README.md,AGENTS.md,project_status_and_backlog.md, and two test files were replaced with documentation placeholders or generic test fixtures without gutting the examples. - F24. Docs are an operator changelog, not user docs. README is now a newcomer-facing user guide, dated validation history moved to
CHANGELOG.md, future work moved toROADMAP.md,CONTRIBUTING.mdanddocs/ARCHITECTURE.mdwere added, andproject_status_and_backlog.mdnow points to the canonical docs. - F25. Config drift.
.env.exampleand compose defaults now match the registry-backedQwen3-30B-A3B-Q4_K_M.gguffilename and the auto-attachedmmproj-Qwen3VL-32B-Instruct-Q8_0.gguf;docker-compose.ymlno longer uses the deprecated top-levelversion:key. - F26. Real readiness probe.
/readyreports database, Redis, Chroma, and Celery worker heartbeat status. Database/Redis/Chroma failures return 503; a missing worker heartbeat returns 200 withstatus: degradedbecause the API can still serve read-only traffic. - F27. AMD GPU detection reports useful memory. ROCm CSV parsing now reads VRAM and GTT used/total pools, sets AMD available memory, and prefers Linux system memory for unified-memory APUs while keeping the Strix Halo
unified_memory_gb >= 96profile heuristic unchanged. - F28. Compose hardcodes host-specific group ids.
docker-compose.amd.ymluses${VIDEO_GROUP_ID:-44}and${RENDER_GROUP_ID:-993}defaults, with.env.exampleguidance for discovering host ids viagetent group video render | cut -d: -f3.
| Path | Tier | Rationale / caveats |
|---|---|---|
AMD Strix Halo (ROCm 7.2, Docker: base + docker-compose.amd.yml) |
Tier 1 | Reference platform; live-validated repeatedly; ROCm-only contract enforced in code. Must pass acceptance before 1.0. |
NVIDIA single/multi-GPU (CUDA, Docker: base + docker-compose.nvidia.yml) |
Tier 1 | Live-validated on a mixed 3090 + RTX PRO 6000 host (March 2026 acceptance log). No NVIDIA hardware in this audit environment; CI covers image build + contract tests, not GPU runtime. |
| Apple Silicon (Metal, host-run, small-model defaults) | Tier 2 | Validated on a 16 GB Mac mini per repo log; host-run only (no Metal in Docker), Celery --pool=solo required. Documented caveats. |
| CPU-only (Docker base compose or host) | Tier 2 | Pipeline runs but the default large-model set is impractical; supported for small models/short clips and functional testing. Needs small-profile defaults (F20). |
| External OpenAI-compatible endpoints (vision/summarization offload) | Tier 2 | Explicitly opt-in, keeps local-first default; validated against llama.cpp/vLLM servers. |
ROCm vLLM runtime (ROCM_LLM_RUNTIME=vllm, INSTALL_VLLM=1) |
Experimental | Repo's own findings: fragile on gfx1151, slow startup, teardown hazards. Keep available, label clearly. |
Canary / Granite ASR (INSTALL_NEMO=1, granite models) |
Experimental | Alternative ASR families; not part of the default path. |
| Vulkan backend enum | Experimental/deprecated | Rejected on Strix Halo by contract; kept only as an env value. Document as unsupported. |
Launch-blocking
- Suite green everywhere: fix F1–F3; one canonical test command documented and used in CI.
- Reproducible builds:
package-lock.json+uv.lockcommitted; Docker builds install from locks;llama-cpp-pythonpinned to a rev; moving model/runtime deps pinned or documented (F5). - CI on every push: backend pytest, frontend lint + typecheck + build, Docker build smoke, plus basic frontend tests for critical flows (F6).
- UI redesign to a coherent design system with dialogs/toasts, loading/empty/error states, light/dark, responsive layout, baseline a11y (F13–F19, F15).
- Close UI↔backend drift: batch UI, job cancel, similar videos, slide images, duplicate visibility (F8–F12, F21).
- Guided first-run: hardware-aware recommended model sets, opt-in downloads with progress/disk/VRAM checks, HF token + pyannote license guidance, fixed setup script (F4, F20).
- Docs split: newcomer README with per-platform quickstarts, CHANGELOG, ROADMAP, CONTRIBUTING, architecture overview; privacy scrub with placeholders (F23–F25).
- Ops:
/readyendpoint with dependency checks; every setting documented + validated;scripts/acceptance.shkept canonical (F26). - Remove the WIP banner (F22) once the above hold.
Post-1.0 / explicitly not blocking
- CLAP fixture promotion for meeting/software-demo separation (research).
- Dynamic residency planner improvements beyond current free-memory placement.
- Incremental recomputation / step-level caching; multi-index retrieval routing; live transcription; action-item external sync.
- Per-user auth/RBAC, MFA, session-device management (single-admin model is intentional at 1.0).
- ROCm vLLM as a default runtime.
- Job progress stays on polling for 1.0 (F11): the WS route remains for automation, but the redesigned UI keeps interval polling — one mechanism to test, no reconnect/auth complexity before launch.
- CPU-only is Tier 2, not Tier 1: the default model set cannot meet a "first successful result" bar on CPU; rather than shrink the product, we ship small-profile defaults + honest docs.
- NVIDIA stays Tier 1 with a documented verification boundary: no NVIDIA hardware is attached to this audit/CI environment; runtime claims rest on the March 2026 live acceptance record, guarded by contract tests and image build CI.
All findings F1–F28 and every launch-blocking checklist item are closed; CI is green on main.
The full 1.0 readiness report (what was tested, what was not, and remaining risks) is summarized here:
- Verified in this cycle: backend suite (224 tests) on the Strix Halo reference machine; frontend
lint/typecheck/build plus 17 component tests; live HTTP walk of auth bootstrap, upload (valid +
rejected), batch create/list, labels, recommendations, download validation, tags, delete,
/health, and/ready; all frontend routes render against a live backend; Docker compose configs validate and the frontend image builds in CI. - Not verified here (documented boundary): GPU model inference end-to-end on ROCm/CUDA/Metal —
no idle GPU/Apple hardware was available to this cycle. These paths keep their contract tests, pinned
runtimes, and prior live-acceptance record; rerun
scripts/acceptance.shon live targets before tagging a release. - Remaining risks: the ruff CI gate covers only fatal/syntax rules (~400 legacy style violations to burn down); ROCm vLLM stays experimental; the packaged CLAP calibration remains conservative; single-admin auth is an intentional 1.0 constraint (RBAC/MFA on the roadmap).
- Slide image serving is contained to the per-video pipeline frames directory and rejects poisoned database paths or symlink escapes.
- GGUF model resolution accepts bare filenames, case-insensitive existing files, and clear read-only download-target failures.
- Video mutation responses preserve sanitized duplicate metadata.
- Batch creation reports accepted videos plus per-file rejection reasons.
/ready?strict=1returns 503 for any failing dependency, including the worker heartbeat.- Setup hardware detection now classifies high-RAM ROCm systems as
strix_halobefore falling back to genericmulti_gpu. - Live Strix Docker validation: first-run admin bootstrap now uses
scripts/bootstrap-admin.shand the setup rejection points operators to supported bootstrap paths. - Live NVIDIA ai-server validation: managed endpoint GPU pins keep host indices in
CUDA_VISIBLE_DEVICESwhile passing CUDA-local ordinals to llama.cpp and vLLM. - Live NVIDIA re-tests (two rounds):
CUDA_VISIBLE_DEVICESdoes not compose across processes — a child re-enumerates the container's physical device namespace — so GPU pins are exported verbatim as physical ids with engine arguments translated to ordinals within the child's own list; a parentCUDA_VISIBLE_DEVICESacts as a deployment allowlist and unresolvable pins fail fast instead of silently falling back to device 0. Vision no longer collides with the summarization card. - Model status now uses the shared local GGUF resolver, including bare-name and case-insensitive cache hits.
- The standalone llama.cpp server wrapper translates extra GPU selector args after role pinning narrows
CUDA_VISIBLE_DEVICES. - Live NVIDIA end-to-end validation: worker-side planner GPU host indices now translate to CUDA-local ordinals under narrowed
CUDA_VISIBLE_DEVICES. - All-invalid batch uploads now return the accumulated per-file rejection reasons in the 400 detail.
Full single-video acceptance PASSED on the multi-GPU NVIDIA host, 3090s only: transcription/embeddings on one card, summarization (Qwen3-30B Q4_K_M at 16k context) on a second, vision (Qwen2.5-VL-7B via vLLM) on a third, with the RTX PRO 6000s and co-tenant workloads untouched throughout and clean teardown. This closes the GPU verification boundary noted above for the NVIDIA Tier 1 path (ROCm inference verification still pends a free window on the Strix reference box). Post-1.0 refinements noted from the run: the runtime planner could pre-filter candidate GPUs to the process's CUDA_VISIBLE_DEVICES so the out-of-visibility fallback (first visible device) is never needed, and first search/ask requests can return one transient 500 before warmup — both cosmetic, neither blocking.