|
| 1 | +--- |
| 2 | +doc_type: runbook |
| 3 | +status: active |
| 4 | +date: 2026-06-21 |
| 5 | +owner: acumenus |
| 6 | +module: infrastructure |
| 7 | +lineage_anchor: false |
| 8 | +supersedes: [] |
| 9 | +superseded_by: null |
| 10 | +related_prs: [] |
| 11 | +related_code: |
| 12 | + - backend/app/Console/Commands/SidecarReadinessCommand.php |
| 13 | + - backend/app/Http/Controllers/Api/V1/HealthController.php |
| 14 | + - deploy.sh |
| 15 | + - docs/lineage/operations/2026-06-21-test-skip-inventory.md |
| 16 | +--- |
| 17 | + |
| 18 | +# Environment Readiness Matrix & Promotion Gates |
| 19 | + |
| 20 | +Closes the Phase 0 item "Record the runtime readiness matrix" and the Phase 8 item |
| 21 | +"Define environment promotion gates for local, staging, and production." It builds |
| 22 | +on `php artisan sidecars:readiness` (runtime sidecar probe) and the |
| 23 | +[test skip inventory](2026-06-21-test-skip-inventory.md) (which modules are |
| 24 | +hosted-only). |
| 25 | + |
| 26 | +## Part A — Service readiness matrix |
| 27 | + |
| 28 | +| Service | Readiness check | Local Docker | Hosted staging | Production | |
| 29 | +|---|---|---|---|---| |
| 30 | +| Backend API | `GET /api/health` (canonical; `HealthController`) | required | required | required | |
| 31 | +| Frontend assets | `frontend/dist/` built + served by nginx/Apache | `deploy.sh --frontend` | required | required (Apache) | |
| 32 | +| Postgres | connection + migrations current | required | required | required | |
| 33 | +| Redis / queues | `sidecars:readiness` (redis PING) + Horizon up | required | required | required | |
| 34 | +| darkstar (R/HADES) | `sidecars:readiness` (`/health`, required) | optional | required | required | |
| 35 | +| python-ai | `sidecars:readiness` (`/health`, required) | optional | required | required | |
| 36 | +| Solr | `/solr/<core>/admin/ping` | optional | required | required | |
| 37 | +| Orthanc / PACS | `sidecars:readiness` (reachability) | optional | hosted smoke | hosted smoke | |
| 38 | +| hecate / fhir-to-cdm / templates | `sidecars:readiness` (reachability) | optional | required | required | |
| 39 | +| anonymizer / SciSpaCy / Llettuce | (no app-side probe; ingestion-template stack) | optional | hosted smoke | hosted smoke | |
| 40 | +| Representative CDM data | row-count probes (see skip inventory) | optional | hosted smoke | required for clinical flows | |
| 41 | + |
| 42 | +"hosted smoke" = validated by a hosted smoke test rather than a local gate; see the |
| 43 | +env-required clusters in the skip inventory. |
| 44 | + |
| 45 | +## Part B — Promotion gates |
| 46 | + |
| 47 | +A build promotes from one tier to the next only when **all** gates for the target |
| 48 | +tier pass. Each gate has a concrete, reproducible check. |
| 49 | + |
| 50 | +| Gate | Check (command / signal) | local→staging | staging→prod | |
| 51 | +|---|---|---|---| |
| 52 | +| Backend health | `curl -fsS $BASE/api/health` → 200 (deploy.sh already smoke-checks this) | required | required | |
| 53 | +| Frontend asset deployment | `deploy.sh --frontend` builds `dist/`; `dist/index.html` present and served (never `npm run build` as the release path) | required | required | |
| 54 | +| Queue workers | Horizon running; `php artisan horizon:status` healthy; `queue:restart` signaled on deploy | required | required | |
| 55 | +| Database migrations | `php artisan migrate --pretend` clean (no pending) after `deploy.sh --db` | required | required | |
| 56 | +| AI / analysis sidecars | `php artisan sidecars:readiness` exits 0 (darkstar + python-ai + redis ready) | required | required | |
| 57 | +| Representative CDM data | CDM row-count probe non-zero for the flows the tier serves | optional | required for clinical flows | |
| 58 | +| PACS / DICOMweb | Orthanc reachable + a hosted PACS smoke (credentials, stats, study browser) | hosted smoke | hosted smoke | |
| 59 | +| Ingestion template smoke | `cd templates && uv run pytest -q` green (env-bound skips documented) | required | required | |
| 60 | +| Bounded test lanes | `cd backend && composer test` green | required | required | |
| 61 | + |
| 62 | +### Running the gate |
| 63 | + |
| 64 | +```bash |
| 65 | +# Runtime sidecar gate (non-zero exit blocks promotion) |
| 66 | +docker compose exec -T php php artisan sidecars:readiness --json |
| 67 | + |
| 68 | +# Bounded test gate |
| 69 | +cd backend && composer test # unit → integration → feature lanes |
| 70 | +cd templates && uv run pytest -q # ingestion templates |
| 71 | + |
| 72 | +# Backend health smoke (deploy.sh performs this automatically) |
| 73 | +curl -fsS https://<host>/api/health |
| 74 | +``` |
| 75 | + |
| 76 | +## Notes |
| 77 | + |
| 78 | +- The `sidecars:readiness` command treats darkstar, python-ai, and redis as |
| 79 | + **required** (non-zero exit) and the rest as reachability-only, so it is safe to |
| 80 | + wire directly into a CI/promotion step. |
| 81 | +- anonymizer / SciSpaCy / Llettuce have no app-side readiness probe today (they |
| 82 | + live in the ingestion-template stack); their promotion signal is the templates |
| 83 | + pytest smoke plus the hosted-only clusters noted in the skip inventory. |
| 84 | +- Production frontend is served by Apache from `frontend/dist/`; a promotion that |
| 85 | + changes the frontend must run `deploy.sh --frontend`, not the Vite dev server. |
0 commit comments