Skip to content

fix: DEBUG-218 populate severity_bucket + assessment_type on crisis_detected emit#133

Merged
MP2EZ merged 1 commit into
developmentfrom
fix/debug-218-crisis-detected-undefined-severity-assessment-type
Jun 6, 2026
Merged

fix: DEBUG-218 populate severity_bucket + assessment_type on crisis_detected emit#133
MP2EZ merged 1 commit into
developmentfrom
fix/debug-218-crisis-detected-undefined-severity-assessment-type

Conversation

@MP2EZ
Copy link
Copy Markdown
Owner

@MP2EZ MP2EZ commented Jun 6, 2026

Closes DEBUG-218

Problem

The vital-interest crisis_detected Supabase telemetry event landed the literal strings severity_bucket="undefined" / assessment_type="undefined" for the highest-acuity safety signal. Root cause: both crisis-detection paths built the CrisisDetection object without severityLevel/assessmentType, and trackCrisisDetection coerced the missing fields via String(undefined). Telemetry-only — the 988/intervention path, detection thresholds, and dedup ordering are unchanged.

AC correction (approved during planning)

The AC claimed the completed-assessment path "already sets both fields" — this was wrong. CrisisDetectionService.detectCrisis built the same Partial<CrisisDetection> cast and also omitted both, so non-Q9 crises (PHQ-9 ≥15 no-Q9, GAD-7 ≥15) also emitted "undefined". Scope was expanded to fix both detection sites (still additive — no threshold / trigger_type change). The two intentionally-divergent detectCrisis implementations were NOT unified.

Changes

  • assessmentStore.ts: set severityLevel + assessmentType (+ secondaryTriggers) on the inline Q9 path AND CrisisDetectionService.detectCrisis, via shared helpers. PHQ-9 → critical if total ≥20 else high; GAD-7 → high; lowercase phq9/gad7 (matches FEAT-129 crisis_detection_daily grouping). Inline severity derives from live calculatePHQ9Score, try/catch'd with a safe high floor so it can never throw into the crisis flow.
  • SupabaseService.trackCrisisDetection: guard required fields — a missing value degrades to an explicit 'unknown' sentinel + high-severity logSecurity and still emits (vital-interest event never dropped), never String(undefined).
  • Reconciled the emit fixture to lowercase 'phq9', dropped as any so the type-checker enforces AssessmentType.

Tests (test-first)

  • crisisTelemetryFields.regression.test.ts (7) — drives the REAL inline + completed paths; boundaries Q9=0/Q9>0, low→high / ≥20→critical, PHQ 15–19→high, GAD≥15→high; asserts no "undefined".
  • crisisTelemetryGuard.unit.test.ts (3) — 'unknown' substitution + high-severity log + no false-positive.
  • Local: typecheck clean, lint:baseline clean, test:safety 71, test:clinical 94, test:unit 398, test:crisis-detection 82. INFRA-214 contracts (durable 5 + emit 3) green.

Maestro Phase 2.5 gate — deliberate override

The path-based gate triggered on the src/features/assessment/ edit and mapped to the q9/phq9/gad7 flows. This is a telemetry-only change: the user-visible contracts those flows pin (Q9 single-alert, PHQ-9 ≥20 completion banner, GAD-7 severe handoff) are provably unchanged — the jest regression confirms the only behavioral delta is the analytics payload on a fire-and-forget event that runs after the alert/intervention. Gate skipped by deliberate human decision (not --skip-e2e).

🤖 Generated with Claude Code

…etected emit

Both crisis-detection paths built the CrisisDetection object without
severityLevel/assessmentType, so SupabaseService.trackCrisisDetection coerced
the missing fields via String(undefined) → the literal "undefined" landed in
analytics_events for the highest-acuity safety signal. Telemetry-only: the
988/intervention path, detection thresholds, and dedup ordering are unchanged.

- assessmentStore: set severityLevel + assessmentType (+ secondaryTriggers) on
  the inline Q9 path AND CrisisDetectionService.detectCrisis. The score-based
  completed path was identically broken — the AC's claim it was already correct
  was wrong; non-Q9 crises (PHQ-9 >=15 no-Q9, GAD-7 >=15) also emitted
  "undefined". Severity derives from the existing total (>=20 critical, else
  high; GAD-7 high) via a shared helper — no threshold/trigger-taxonomy change.
- SupabaseService.trackCrisisDetection: guard required categorical fields — a
  missing value degrades to an explicit 'unknown' sentinel + high-severity log
  and still emits (vital-interest event never dropped), never String(undefined).
- Tests (test-first): regression suite drives the real inline + completed paths
  asserting no "undefined"; guard unit test pins the 'unknown' substitution;
  reconciled the emit fixture to the lowercase 'phq9' AssessmentType union.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@MP2EZ MP2EZ merged commit bd03447 into development Jun 6, 2026
22 checks passed
@MP2EZ MP2EZ deleted the fix/debug-218-crisis-detected-undefined-severity-assessment-type branch June 6, 2026 09:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant