[Mac local stack] Full site flow on the M5 — quiz generation + embeddings + book upload pipeline in mac-dev-up.sh #464

Closed
opened 2026-07-08 23:43:09 +00:00 by spikerj · 4 comments
Owner

Follow-up to #359 (closed; epic #346). #359 delivered the Art Studio flow on the Mac: scripts/mac-dev-up.sh brings up compose infra + native API + native ArtPipeProcessor (MPS). This ticket extends that to the entire site flow, so quiz generation can be tested locally alongside Art Studio. All work is in spikersoft-backend unless noted.

Why each piece is needed (traced, not speculative)

  • SpikerSoft.EventHandlers.QuizGeneration reads pre-extracted page text from Mongo (QuizGenerationWorkerService — "no PDF re-parsing needed"). Without the upload pipeline having run, there is nothing to generate quizzes from. The producer chain is: upload-coordinator → security-scanner (ClamAV) → metadata-extractor → book-management / file-movement, with SpikerSoft.EventHandlers.Embeddings storing pages + vectors (BookPageStorageService).
  • AI:EnableRAG defaults to true and queries RediSearch KNN (RedisVectorSearchService), which needs the embeddings worker to have populated the index. The mac compose override's single-node Redis Stack already loads the redisearch module.
  • Both quiz + embeddings csprojs hard-reference LLamaSharp.Backend.Cuda12, which cannot load on macOS.

Task 1 — LLamaSharp Metal backend (only real code change)

In SpikerSoft.EventHandlers.QuizGeneration/SpikerSoft.EventHandlers.QuizGeneration.csproj and SpikerSoft.EventHandlers.Embeddings/SpikerSoft.EventHandlers.Embeddings.csproj, make the backend package conditional:

<PackageReference Include="LLamaSharp.Backend.Cuda12" Version="0.27.0" Condition="!$([MSBuild]::IsOsPlatform('OSX'))" />
<PackageReference Include="LLamaSharp.Backend.Cpu" Version="0.27.0" Condition="$([MSBuild]::IsOsPlatform('OSX'))" />

Backend.Cpu ships Metal-enabled llama.cpp binaries for osx-arm64. Keep the existing comment about the PrivateAssets defense-in-depth. Verify Metal engages at runtime (llama.cpp logs ggml_metal / offloaded layers with GpuLayerCount=99). Note: this changes the Linux/CUDA build not at all — Docker images build on Linux and keep Cuda12.

Task 2 — GGUF models on the host

Add scripts/mac-dev-models.sh (idempotent, curl/hf download into ~/ai-models/gguf):

  • gemma-3n-E2B-it-Q8_0.gguf (Fast preset, ~5 GB)
  • gemma-3-12b-it-Q4_K_M.gguf (Balanced preset — default, ~9 GB)
  • nomic-embed-text-v2-moe.f16.gguf (embeddings)
  • Phi-4-reasoning-plus-Q4_K_M.gguf (Quality preset) optional / --all

Appsettings paths are container paths (/app/ai/...), so the native workers must be launched with AI__Models__Fast__Path, AI__Models__Balanced__Path, AI__Models__Quality__Path, and AI__EmbeddingModelPath overrides pointing at the host files.

Task 3 — Upload pipeline containers in the mac compose override

Add to docker-compose.mac.yml and to COMPOSE_SERVICES in scripts/mac-dev-common.sh: upload-coordinator, security-scanner, metadata-extractor, book-management, file-movement, clamav.

  • clamav: add platform: linux/amd64 (no arm64 image; runs under Rosetta — this was the documented workaround in the mac.yml header, now wired in for real). First boot downloads signatures (start_period 300s already in base file).
  • The base file's volume mounts are Windows paths (C:\temp\spikersoft-api-local\...). Override them in the mac file to a shared host dir, e.g. ~/spikersoft-local/{uploads,ebooks,blogs,dlls,code,assets,quarantine}.
  • The host-side API launched by mac-dev-up.sh must write uploads into that same shared dir — add the corresponding path config overrides to the api_env block (find the upload/asset root keys in SpikerSoft.Api appsettings).

Task 4 — Native quiz + embeddings workers in mac-dev-up.sh

New flag --full (implies existing behavior plus):

  • Build + launch SpikerSoft.EventHandlers.QuizGeneration and SpikerSoft.EventHandlers.Embeddings host-side, same nohup/pid-file/log pattern as the API and worker (.mac-dev/quiz.pid, .mac-dev/embeddings.pid, logs in .mac-dev/logs/).
  • Env for both: ASPNETCORE_ENVIRONMENT=Development, Mongo__ConnectionString=mongodb://localhost:27117/..., RabbitMQ__HostName=localhost, Redis__ConnectionString=localhost:6380,... (embeddings), Seq__ServerUrl=http://localhost:5341, Jaeger__EndPoint=http://localhost:4317, GpuScheduling__Mode=dedicated (single-user laptop; no coordinator arbitration needed), model path overrides from Task 2, distinct Kestrel ports for healthz (avoid 8080 — the art worker owns it; suggest 8180/8181).
  • Preflight: warn when GGUFs are missing (mirror the venv warning pattern) and point at scripts/mac-dev-models.sh.
  • scripts/mac-dev-down.sh stops both.

Task 5 — End-to-end smoke

Add scripts/mac-dev-smoke-quiz.sh (or extend mac-dev-smoke.sh): upload a small PDF via the API (HTTPS :5291, multipart), poll Mongo until pre-extracted pages exist for the book, trigger quiz generation via the API, poll until the quiz document appears; print timings. If the RAG/RediSearch path misbehaves on single-node Redis Stack, fall back to AI__EnableRAG=false for the quiz worker and note it in the doc.

Task 6 — Docs

Update docs/mac-local-stack.md: full-flow recipe (mac-dev-models.sh once → mac-dev-up.sh --full), download sizes, shared-dir layout, ClamAV/Rosetta caveat, healthz port map.

Out of scope

  • image-description (Qwen3-VL) on MPS — possible natively via transformers, not needed for quiz or art flows; separate ticket if wanted.
  • CUDA-only art lanes (TripoSG, Hunyuan3DPaint) — no Mac path exists; production hardware track covers these.

Acceptance

On the M5 with venvs + Blender already set up per #359: scripts/mac-dev-models.sh && scripts/mac-dev-up.sh --full brings everything up; uploading a PDF through the local site produces an available book; requesting a quiz on it returns generated questions using Metal-accelerated gemma (verify offload in the quiz log); the Art Studio smoke from #359 still passes; mac-dev-down.sh --all tears down clean.

Follow-up to #359 (closed; epic #346). #359 delivered the Art Studio flow on the Mac: `scripts/mac-dev-up.sh` brings up compose infra + native API + native ArtPipeProcessor (MPS). This ticket extends that to the **entire site flow**, so quiz generation can be tested locally alongside Art Studio. All work is in `spikersoft-backend` unless noted. ## Why each piece is needed (traced, not speculative) - `SpikerSoft.EventHandlers.QuizGeneration` reads **pre-extracted page text from Mongo** (`QuizGenerationWorkerService` — "no PDF re-parsing needed"). Without the upload pipeline having run, there is nothing to generate quizzes from. The producer chain is: upload-coordinator → security-scanner (ClamAV) → metadata-extractor → book-management / file-movement, with `SpikerSoft.EventHandlers.Embeddings` storing pages + vectors (`BookPageStorageService`). - `AI:EnableRAG` defaults to `true` and queries RediSearch KNN (`RedisVectorSearchService`), which needs the embeddings worker to have populated the index. The mac compose override's single-node Redis Stack already loads the redisearch module. - Both quiz + embeddings csprojs hard-reference `LLamaSharp.Backend.Cuda12`, which cannot load on macOS. ## Task 1 — LLamaSharp Metal backend (only real code change) In `SpikerSoft.EventHandlers.QuizGeneration/SpikerSoft.EventHandlers.QuizGeneration.csproj` and `SpikerSoft.EventHandlers.Embeddings/SpikerSoft.EventHandlers.Embeddings.csproj`, make the backend package conditional: ```xml <PackageReference Include="LLamaSharp.Backend.Cuda12" Version="0.27.0" Condition="!$([MSBuild]::IsOsPlatform('OSX'))" /> <PackageReference Include="LLamaSharp.Backend.Cpu" Version="0.27.0" Condition="$([MSBuild]::IsOsPlatform('OSX'))" /> ``` `Backend.Cpu` ships Metal-enabled llama.cpp binaries for osx-arm64. Keep the existing comment about the PrivateAssets defense-in-depth. Verify Metal engages at runtime (llama.cpp logs `ggml_metal` / offloaded layers with `GpuLayerCount=99`). Note: this changes the Linux/CUDA build not at all — Docker images build on Linux and keep Cuda12. ## Task 2 — GGUF models on the host Add `scripts/mac-dev-models.sh` (idempotent, curl/hf download into `~/ai-models/gguf`): - `gemma-3n-E2B-it-Q8_0.gguf` (Fast preset, ~5 GB) - `gemma-3-12b-it-Q4_K_M.gguf` (Balanced preset — default, ~9 GB) - `nomic-embed-text-v2-moe.f16.gguf` (embeddings) - `Phi-4-reasoning-plus-Q4_K_M.gguf` (Quality preset) optional / `--all` Appsettings paths are container paths (`/app/ai/...`), so the native workers must be launched with `AI__Models__Fast__Path`, `AI__Models__Balanced__Path`, `AI__Models__Quality__Path`, and `AI__EmbeddingModelPath` overrides pointing at the host files. ## Task 3 — Upload pipeline containers in the mac compose override Add to `docker-compose.mac.yml` and to `COMPOSE_SERVICES` in `scripts/mac-dev-common.sh`: `upload-coordinator`, `security-scanner`, `metadata-extractor`, `book-management`, `file-movement`, `clamav`. - `clamav`: add `platform: linux/amd64` (no arm64 image; runs under Rosetta — this was the documented workaround in the mac.yml header, now wired in for real). First boot downloads signatures (start_period 300s already in base file). - The base file's volume mounts are Windows paths (`C:\temp\spikersoft-api-local\...`). Override them in the mac file to a shared host dir, e.g. `~/spikersoft-local/{uploads,ebooks,blogs,dlls,code,assets,quarantine}`. - The host-side API launched by mac-dev-up.sh must write uploads into that same shared dir — add the corresponding path config overrides to the `api_env` block (find the upload/asset root keys in `SpikerSoft.Api` appsettings). ## Task 4 — Native quiz + embeddings workers in mac-dev-up.sh New flag `--full` (implies existing behavior plus): - Build + launch `SpikerSoft.EventHandlers.QuizGeneration` and `SpikerSoft.EventHandlers.Embeddings` host-side, same nohup/pid-file/log pattern as the API and worker (`.mac-dev/quiz.pid`, `.mac-dev/embeddings.pid`, logs in `.mac-dev/logs/`). - Env for both: `ASPNETCORE_ENVIRONMENT=Development`, `Mongo__ConnectionString=mongodb://localhost:27117/...`, `RabbitMQ__HostName=localhost`, `Redis__ConnectionString=localhost:6380,...` (embeddings), `Seq__ServerUrl=http://localhost:5341`, `Jaeger__EndPoint=http://localhost:4317`, `GpuScheduling__Mode=dedicated` (single-user laptop; no coordinator arbitration needed), model path overrides from Task 2, distinct Kestrel ports for healthz (avoid 8080 — the art worker owns it; suggest 8180/8181). - Preflight: warn when GGUFs are missing (mirror the venv warning pattern) and point at `scripts/mac-dev-models.sh`. - `scripts/mac-dev-down.sh` stops both. ## Task 5 — End-to-end smoke Add `scripts/mac-dev-smoke-quiz.sh` (or extend mac-dev-smoke.sh): upload a small PDF via the API (HTTPS :5291, multipart), poll Mongo until pre-extracted pages exist for the book, trigger quiz generation via the API, poll until the quiz document appears; print timings. If the RAG/RediSearch path misbehaves on single-node Redis Stack, fall back to `AI__EnableRAG=false` for the quiz worker and note it in the doc. ## Task 6 — Docs Update `docs/mac-local-stack.md`: full-flow recipe (`mac-dev-models.sh` once → `mac-dev-up.sh --full`), download sizes, shared-dir layout, ClamAV/Rosetta caveat, healthz port map. ## Out of scope - image-description (Qwen3-VL) on MPS — possible natively via transformers, not needed for quiz or art flows; separate ticket if wanted. - CUDA-only art lanes (TripoSG, Hunyuan3DPaint) — no Mac path exists; production hardware track covers these. ## Acceptance On the M5 with venvs + Blender already set up per #359: `scripts/mac-dev-models.sh && scripts/mac-dev-up.sh --full` brings everything up; uploading a PDF through the local site produces an available book; requesting a quiz on it returns generated questions using Metal-accelerated gemma (verify offload in the quiz log); the Art Studio smoke from #359 still passes; `mac-dev-down.sh --all` tears down clean.
spikerj added the enhancement label 2026-07-08 23:43:27 +00:00
Author
Owner

Status 2026-07-08: implementation complete, committed locally on spikersoft-backend branch feat/464-mac-full-site-flow (add055b). Paused before the full acceptance run — home internet is currently unusable (~200 KB/s, flaky), which blocks the GGUF downloads and the in-Docker NuGet restores.

Done & verified on the M5

  • Task 1LLamaSharp.Backend.Cuda12 is now Condition="!IsOsPlatform('OSX')" with Backend.Cpu on OSX in both csprojs. Both workers restore/build on macOS and runtimes/osx-arm64/native/libggml-metal.dylib is in the output (Metal binaries confirmed). Linux/Docker builds unchanged.
  • Task 2scripts/mac-dev-models.sh (idempotent, curl resume, --all for Phi-4). Note: the README's google//bartowski/ HF URLs are gated or 404 today; switched to the ungated unsloth/ + nomic-ai/ mirrors (exact filename matches verified via HF API; README updated).
  • Task 3 — pipeline services in docker-compose.mac.yml (clamav platform: linux/amd64), Windows mounts replaced with $MAC_SHARED_DIR (~/spikersoft-local). Design note: the pipeline messages carry absolute StagingPaths and metadata-extractor hardcodes /app/ebooks in code, so each container mounts the shared dir at both /app/<subdir> and the identical absolute host path (mirror mount). Merged compose config validates. Kept the pipeline services out of the base COMPOSE_SERVICES (art-only bring-up shouldn't build 5 images / run Rosetta ClamAV) — they're a separate UPLOAD_PIPELINE_SERVICES list appended by --full.
  • Task 4mac-dev-up.sh --full builds+launches both native workers (pids/logs in .mac-dev/), GGUF preflight warning, health waits on :8180/:8181; mac-dev-down.sh stops them (exercised). Extra code change the ticket needed: WithKestrel now honors a Kestrel:Port config override — it calls UseUrls, which env vars can't override, so 8180/8181 was impossible without it. Containers don't set the key; deployed behavior unchanged. Also added MAC_DEV_ENABLE_RAG=false as the RediSearch fallback knob.
  • Task 5scripts/mac-dev-smoke-quiz.sh: generates a text-only PDF via cupsfilter (books with images wait ~30 min on the out-of-scope image-description worker — documented), uploads as test user, approves as the seeded e2e.staff account, follows the workflow in Mongo (status → book-pages → EmbeddingsComplete → quiz doc), prints timings + sample question. Second extra code change: ApproveUpload requires the staff role, which the role-less test user lacks — under UseTestAuthentication=true the real Keycloak JWT bearer scheme now stays registered alongside the test scheme. Verified live on the M5: token-less → 403 on GET /api/book/pending (art-studio behavior from #359 unchanged), real e2e.staff token (password grant, spikersoft-backend client) → 200. Keycloak only contacted when a Bearer token is present, so the stack stays offline-capable. Bonus: a locally-served Angular app can now hit the local API with real logins.
  • Task 6docs/mac-local-stack.md §7: recipe, model table with sizes/sources, healthz port map (API 5290/5291, art 8080, quiz 8180, embeddings 8181), shared-dir layout, ClamAV/Rosetta + GET /api/book/{id}/file caveats.
  • SpikerSoft.Tests.Unit: 11437 passed, 4 failed — the identical 4 fail on unmodified master (environmental: GitService per-user repo ×2, Python curriculum ×2). shellcheck clean.

Blocked on connectivity (resume when internet is good)

  1. scripts/mac-dev-models.sh — resumes the three .part files already in ~/ai-models/gguf (downloads smallest-first: nomic → gemma-3n → gemma-12b).
  2. docker compose -f docker-compose.yml -f docker-compose.mac.yml -f docker-compose.redisport.yml build upload-coordinator security-scanner metadata-extractor book-management file-movement (first attempt died in in-container dotnet restore) — or just let mac-dev-up.sh --full build them.
  3. scripts/mac-dev-up.sh --fullscripts/mac-dev-smoke-quiz.sh (needs spikersoft-angular/.env.e2e staff creds — already present on the M5), verify ggml_metal offload in .mac-dev/logs/quiz.log, re-run the #359 art smoke, mac-dev-down.sh --all.
  4. Push branch + open the PR once the smoke passes.
**Status 2026-07-08: implementation complete, committed locally on `spikersoft-backend` branch `feat/464-mac-full-site-flow` (add055b). Paused before the full acceptance run — home internet is currently unusable (~200 KB/s, flaky), which blocks the GGUF downloads and the in-Docker NuGet restores.** ### Done & verified on the M5 - **Task 1** — `LLamaSharp.Backend.Cuda12` is now `Condition="!IsOsPlatform('OSX')"` with `Backend.Cpu` on OSX in both csprojs. Both workers restore/build on macOS and `runtimes/osx-arm64/native/libggml-metal.dylib` is in the output (Metal binaries confirmed). Linux/Docker builds unchanged. - **Task 2** — `scripts/mac-dev-models.sh` (idempotent, curl resume, `--all` for Phi-4). Note: the README's `google/`/`bartowski/` HF URLs are gated or 404 today; switched to the ungated `unsloth/` + `nomic-ai/` mirrors (exact filename matches verified via HF API; README updated). - **Task 3** — pipeline services in `docker-compose.mac.yml` (clamav `platform: linux/amd64`), Windows mounts replaced with `$MAC_SHARED_DIR` (~/spikersoft-local). Design note: the pipeline messages carry **absolute** StagingPaths and metadata-extractor hardcodes `/app/ebooks` in code, so each container mounts the shared dir at both `/app/<subdir>` and the identical absolute host path (mirror mount). Merged compose config validates. Kept the pipeline services out of the base `COMPOSE_SERVICES` (art-only bring-up shouldn't build 5 images / run Rosetta ClamAV) — they're a separate `UPLOAD_PIPELINE_SERVICES` list appended by `--full`. - **Task 4** — `mac-dev-up.sh --full` builds+launches both native workers (pids/logs in `.mac-dev/`), GGUF preflight warning, health waits on :8180/:8181; `mac-dev-down.sh` stops them (exercised). Extra code change the ticket needed: `WithKestrel` now honors a `Kestrel:Port` config override — it calls `UseUrls`, which env vars can't override, so 8180/8181 was impossible without it. Containers don't set the key; deployed behavior unchanged. Also added `MAC_DEV_ENABLE_RAG=false` as the RediSearch fallback knob. - **Task 5** — `scripts/mac-dev-smoke-quiz.sh`: generates a **text-only** PDF via cupsfilter (books with images wait ~30 min on the out-of-scope image-description worker — documented), uploads as test user, approves as the seeded `e2e.staff` account, follows the workflow in Mongo (status → book-pages → EmbeddingsComplete → quiz doc), prints timings + sample question. **Second extra code change:** `ApproveUpload` requires the staff role, which the role-less test user lacks — under `UseTestAuthentication=true` the real Keycloak JWT bearer scheme now stays registered alongside the test scheme. Verified live on the M5: token-less → 403 on `GET /api/book/pending` (art-studio behavior from #359 unchanged), real `e2e.staff` token (password grant, `spikersoft-backend` client) → 200. Keycloak only contacted when a Bearer token is present, so the stack stays offline-capable. Bonus: a locally-served Angular app can now hit the local API with real logins. - **Task 6** — `docs/mac-local-stack.md` §7: recipe, model table with sizes/sources, healthz port map (API 5290/5291, art 8080, quiz 8180, embeddings 8181), shared-dir layout, ClamAV/Rosetta + `GET /api/book/{id}/file` caveats. - `SpikerSoft.Tests.Unit`: 11437 passed, 4 failed — the identical 4 fail on unmodified master (environmental: GitService per-user repo ×2, Python curriculum ×2). shellcheck clean. ### Blocked on connectivity (resume when internet is good) 1. `scripts/mac-dev-models.sh` — resumes the three `.part` files already in `~/ai-models/gguf` (downloads smallest-first: nomic → gemma-3n → gemma-12b). 2. `docker compose -f docker-compose.yml -f docker-compose.mac.yml -f docker-compose.redisport.yml build upload-coordinator security-scanner metadata-extractor book-management file-movement` (first attempt died in in-container `dotnet restore`) — or just let `mac-dev-up.sh --full` build them. 3. `scripts/mac-dev-up.sh --full` → `scripts/mac-dev-smoke-quiz.sh` (needs `spikersoft-angular/.env.e2e` staff creds — already present on the M5), verify `ggml_metal` offload in `.mac-dev/logs/quiz.log`, re-run the #359 art smoke, `mac-dev-down.sh --all`. 4. Push branch + open the PR once the smoke passes.
Author
Owner

Task 1 done — merged to master in spikersoft-backend PR #188 (commit d0e65d8).

LLamaSharp.Backend.Cuda12 is now OS-conditional (!IsOsPlatform('OSX')) with LLamaSharp.Backend.Cpu added on OSX, in both SpikerSoft.EventHandlers.QuizGeneration.csproj and SpikerSoft.EventHandlers.Embeddings.csproj. Backend.Cpu ships Metal-enabled llama.cpp binaries for osx-arm64. The Linux/CUDA production build is unchanged (negated condition + Docker builds on Linux). Verified locally on macOS arm64: QuizGeneration, Embeddings, and SpikerSoft.Tests.Unit all build 0 errors.

Leaving this ticket open — Tasks 2–6 (scripts/mac-dev-models.sh, the mac compose upload-pipeline services, the --full native quiz+embeddings launch in mac-dev-up.sh, the E2E smoke script, and docs) remain, and are in progress on branch feat/464-mac-full-site-flow. Runtime Metal-offload verification depends on the Task 2 GGUFs.

**Task 1 done** — merged to `master` in spikersoft-backend PR #188 (commit `d0e65d8`). `LLamaSharp.Backend.Cuda12` is now OS-conditional (`!IsOsPlatform('OSX')`) with `LLamaSharp.Backend.Cpu` added on OSX, in both `SpikerSoft.EventHandlers.QuizGeneration.csproj` and `SpikerSoft.EventHandlers.Embeddings.csproj`. Backend.Cpu ships Metal-enabled llama.cpp binaries for osx-arm64. The Linux/CUDA production build is unchanged (negated condition + Docker builds on Linux). Verified locally on macOS arm64: QuizGeneration, Embeddings, and `SpikerSoft.Tests.Unit` all build 0 errors. Leaving this ticket **open** — Tasks 2–6 (`scripts/mac-dev-models.sh`, the mac compose upload-pipeline services, the `--full` native quiz+embeddings launch in `mac-dev-up.sh`, the E2E smoke script, and docs) remain, and are in progress on branch `feat/464-mac-full-site-flow`. Runtime Metal-offload verification depends on the Task 2 GGUFs.
Author
Owner

Acceptance run complete (M5, overnight 2026-07-09) — everything passes. Branch feat/464-mac-full-site-flow (00f672d) pushed to spikersoft-backend; PR not yet opened (waiting for Joey's go-ahead).

  • mac-dev-models.sh → 3 GGUFs, 12.2 GB (resumed the .part files once the connection recovered; ~1 MB/s overnight)
  • mac-dev-up.sh --full → infra + 6 pipeline containers + API + art/quiz/embeddings workers healthy in ~21 s (after one-time image builds)
  • mac-dev-smoke-quiz.shPASSED: upload → e2e.staff approval (real Keycloak token against the test-auth API) → ClamAV scan t+4 s → 8 pre-extracted pages in book-pages t+8 s → embeddings + BookPageChunk:* RediSearch vectors t+18 s → 9 RAG-grounded questions t+114 s (sample: "According to the provided text, what is a primary function of message brokers like RabbitMQ?")
  • Metal offload confirmed: every gemma layer assigned to device MTL0 in quiz.log; ggml_metal_device_init: GPU family MTLGPUFamilyApple10
  • #359 art smoke still passes: Prop plan, 5 stages, 47 s, all artifacts in GridFS
  • mac-dev-down.sh --all tears down clean (no orphan processes/containers); restart-after-teardown verified — stack left running
  • One extra fix found during the run: the base compose ClamAV healthcheck (/usr/local/bin/clamd --ping) doesn't exist in current clamav images, so the container reported unhealthy forever — the mac override now probes with clamdcheck.sh (fix included in the branch)

Remaining: open the PR from feat/464-mac-full-site-flow → master, merge after CI, then comment+close this ticket per the tracker workflow.

**Acceptance run complete (M5, overnight 2026-07-09) — everything passes. Branch `feat/464-mac-full-site-flow` (00f672d) pushed to `spikersoft-backend`; PR not yet opened (waiting for Joey's go-ahead).** - `mac-dev-models.sh` → 3 GGUFs, 12.2 GB (resumed the `.part` files once the connection recovered; ~1 MB/s overnight) - `mac-dev-up.sh --full` → infra + 6 pipeline containers + API + art/quiz/embeddings workers healthy in ~21 s (after one-time image builds) - `mac-dev-smoke-quiz.sh` → **PASSED**: upload → `e2e.staff` approval (real Keycloak token against the test-auth API) → ClamAV scan t+4 s → 8 pre-extracted pages in `book-pages` t+8 s → embeddings + `BookPageChunk:*` RediSearch vectors t+18 s → **9 RAG-grounded questions t+114 s** (sample: "According to the provided text, what is a primary function of message brokers like RabbitMQ?") - Metal offload confirmed: every gemma layer `assigned to device MTL0` in quiz.log; `ggml_metal_device_init: GPU family MTLGPUFamilyApple10` - #359 art smoke still passes: Prop plan, 5 stages, 47 s, all artifacts in GridFS - `mac-dev-down.sh --all` tears down clean (no orphan processes/containers); restart-after-teardown verified — stack left running - One extra fix found during the run: the base compose ClamAV healthcheck (`/usr/local/bin/clamd --ping`) doesn't exist in current clamav images, so the container reported unhealthy forever — the mac override now probes with `clamdcheck.sh` (fix included in the branch) Remaining: open the PR from `feat/464-mac-full-site-flow` → master, merge after CI, then comment+close this ticket per the tracker workflow.
Author
Owner

Resolved in spikersoft-backend PR #198 (merged; Task 1 in PR #188): mac-dev-up.sh --full brings up the entire site flow on the M5 — quiz generation + embeddings + book upload pipeline — with OS-conditional LLamaSharp Metal backend. Acceptance-verified 2026-07-09. Closing.

Resolved in spikersoft-backend PR #198 (merged; Task 1 in PR #188): mac-dev-up.sh --full brings up the entire site flow on the M5 — quiz generation + embeddings + book upload pipeline — with OS-conditional LLamaSharp Metal backend. Acceptance-verified 2026-07-09. Closing.
Sign in to join this conversation.