146 lines
5.8 KiB
Markdown
146 lines
5.8 KiB
Markdown
# 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 central’s 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.
|