Files
vigilcare-clinical/docs/resilience/phase-24-verification-notes.md
T
2026-06-24 03:01:00 +08:00

146 lines
5.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Phase 24 verification notes
Notes from getting `scripts/run-phase24-verification.sh` to pass against local Docker + dev central API (`http://localhost:5270`).
## Automated verification
```bash
./scripts/run-phase24-verification.sh
```
Useful env overrides:
| Variable | Purpose |
|----------|---------|
| `SKIP_DOCKER=1` | Stack already up; skip compose |
| `SKIP_PHASE_A=1` | Skip central baseline replay |
| `SCENARIO_SPEED=0` | Instant replay (default) |
| `KEEP_CENTRAL_DOWN=1` | Leave central stopped after Phase B (debug) |
Companion script: `scripts/mint-gateway-jwt.sh` — dev JWT for gateway (`issuer: vigilcare-gateway`).
---
## Fixes applied during verification
### 1. Gateway encounter missing after Phase A
**Symptom:** Phase B could not find encounter on gateway.
**Cause:** `docker compose up -d` without recreate did not re-run `SyncOnceAsync` after central had new encounters.
**Fix:** Script calls `docker compose up -d --force-recreate ward-gateway-api` in `configure_gateway_sync` so sync runs on a fresh gateway container.
---
### 2. Phase B observation POST returned 400
**Symptom:** Gateway rejected observation batches from simulator.
**Cause:** Central API accepts batch ingest; gateway expects a **single** observation per POST with `observationCode` (not centrals batch shape).
**Fix:** `VigilCareApiClient.SendObservationBatchAsync` — gateway path posts one observation at a time using gateway field names.
---
### 3. Phase B `recordedAt` rejected (future timestamp)
**Symptom:** 400 — timestamp more than ~5 minutes in the future.
**Cause:** `--speed 0` uses scenario `offsetMinutes` as simulated future times; gateway validates `recordedAt` against wall clock.
**Fix:** `ReplayEngine` uses `DateTimeOffset.UtcNow` for observations when `Target == Gateway`.
**Trade-off:** Gateway replay does not preserve simulated timeline spacing at speed 0; acceptable for outage demo (alerts still fire on values).
---
### 4. No critical potassium alert at K+ 6.1
**Symptom:** Only warning-tier alert; Phase B ack step had nothing to match.
**Cause:** Seeded threshold `CriticalHigh` for potassium is **6.5 mEq/L**; 6.1 is above warning (5.5) but below critical.
**Fix:** Scenario `ward-outage-reconnect-01.json` — critical observation value **6.1 → 6.8**.
---
### 5. Alert ack / jq verification failed (alert type mismatch)
**Symptom:** `TryAcknowledgeAlertAsync` returned false; jq filters found no alert.
**Cause:** API stores/returns enum-style names (e.g. `CriticalPotassiumMeqL`); scenario uses `CRITICAL_POTASSIUM_MEQ_L`.
**Fix:** `VigilCareApiClient.IsMatchingAlertType` — flexible match (case, underscores, suffix).
**Fix:** Verification script uses jq filters that accept both naming styles.
---
### 6. `acknowledgedBy` was `nurse.demo` instead of `RN-Wu`
**Symptom:** After gateway ack, synced alert on central showed JWT subject, not scenario nurse.
**Cause:** Gateway `AcknowledgeAlertRequest` had no body field for clinician; controller used `User.Identity.Name` only. Stale Docker image also hid fixes until rebuild.
**Fix:** Optional `clinicianId` on gateway ack request; controller uses `req.ClinicianId ?? User.Identity?.Name`. Script rebuilds gateway image before run.
---
### 7. Phase C verify timeout
**Symptom:** Script gave up before central showed synced ack with `RN-Wu`.
**Cause:** Central restart + gateway sync can exceed 120s on a loaded machine.
**Fix:** Poll up to **180s** for alert with `syncedFromGateway` and `acknowledgedBy = RN-Wu`.
---
### 8. Phase A central ack fails at `--speed 0` (non-fatal in script)
**Symptom:** Phase A `alert_ack` against central sometimes failed before the poll fix.
**Cause:** Alert pipeline is async; at speed 0 the ack event could run before the critical alert row existed.
**Fix:** Central replay now polls for up to 30s before posting `alert_ack` (`TryAcknowledgeAlertAsync` with `waitForAlert`). The verification script still treats Phase A ack as non-fatal; Phase B (gateway outage path) remains the authoritative ack/sync test.
---
## Code changes summary (already merged)
| Area | Files |
|------|--------|
| Scenario + schema | `ward-outage-reconnect-01.json`, `schema.json`, `ScenarioValidator.cs` |
| Gateway replay | `ReplayOptions.cs`, `ReplayCommand.cs`, `ReplayEngine.cs`, `VigilCareApiClient.cs` |
| Gateway ack attribution | `AcknowledgeAlertRequest.cs`, `AcknowledgeAlertRequestValidator.cs`, `AlertsController.cs` |
| Tests | `WardGatewayLocalPathTests.cs` |
| Automation | `run-phase24-verification.sh`, `mint-gateway-jwt.sh` |
| Docs | `simulator-guide.md` §10, phase-24 plan footnote on gateway vs central ack |
---
## Remaining doc / optional code follow-ups
| Item | Priority | Notes |
|------|----------|--------|
| `phase-24-plan.md` embedded scenario snippet still showed K+ 6.1 | Doc | Updated to 6.8 to match scenario + thresholds |
| `ext-climate-resilience-roadmap.md` referenced `verify-phase-24.ps1` | Doc | Updated to `run-phase24-verification.sh` |
| Central async ack at speed 0 | Done | `ReplayEngine` polls up to 30s before central `alert_ack` |
| Gateway has no `/auth/login` | By design | Use `--gateway-token` / `mint-gateway-jwt.sh` |
| `CentralApiOptions` default port 5080 vs dev 5270 | OK | Docker compose overrides via `host.docker.internal:5270` |
| README mention of Phase 24 script | Done | Ward outage section + verification script list |
| Gateway mode unit tests | Optional | No simulator tests for `--gateway` path yet |
---
## Expected pass criteria (Phase C)
After central restarts:
1. Buffered alert appears on central with `syncedFromGateway` (or equivalent sync marker).
2. `acknowledgedBy` = **RN-Wu** (not gateway JWT subject).
3. Gateway buffer depth returns to **0** (or heartbeat shows no pending acks).
Last successful run: `./scripts/run-phase24-verification.sh` with `SKIP_DOCKER=1` — all phases passed.