AI Triage
The headline feature. Click Suggest triage on any NEW request and
Claude Haiku returns a structured triage result in about a second.
What you get back
{
"category": "EMERGENCY_SAFETY",
"urgency": "EMERGENCY",
"confidence": 0.94,
"reasoning": "Headaches + nausea + yellow gas flame reads as possible CO exposure — treat as life-safety.",
"suggestedActions": [
"Call the tenant and tell them to open windows + leave the unit",
"Dispatch a licensed gas fitter within 4 hours",
"Close any rooms containing the gas heater until certified"
],
"modelVersion": "claude-haiku-4-5@prompt-v2"
}
- Category:
PLUMBING/ELECTRICAL/APPLIANCE/HEATING_COOLING/STRUCTURAL/PEST/SECURITY/GARDEN/CLEANING/EMERGENCY_SAFETY/OTHER. - Urgency:
EMERGENCY(4h SLA) /URGENT(24h) /NORMAL(3d) /LOW(7d). - Confidence: 0.0 – 1.0. Below 0.7 we show a Human triage required badge — you should not just click accept.
- Reasoning: one sentence. Shown verbatim in the review drawer so the PM sees why Claude picked what it picked.
- Suggested actions: 2–4 items in priority order. These drive the drawer's "Next steps" list and make Claude's suggestion actionable, not just a classifier output.
The review → apply loop
- Click Suggest triage on a NEW request.
- The form pre-populates with Claude's picks (category dropdown, urgency radio). You can override either.
- The reasoning + actions appear below the form.
- Click Apply triage. The request moves to
TRIAGED. The SLA clock starts based on urgency (see SLA Clock).
The form auto-syncs when a new suggestion comes in — if you re-click Suggest triage after editing, the dropdowns update to Claude's new picks.
The "Human triage required" badge
Shown when:
- Confidence < 0.7, OR
- The Claude call failed and the heuristic fallback was used, OR
- The circuit breaker is open (3 consecutive Claude failures in a row).
Don't ignore it. Read the tenant text. Apply your own judgement.
Heuristic fallback
If Claude is unavailable, we fall back to a deterministic keyword-rule classifier:
- gas / carbon monoxide / smoke / fire →
EMERGENCY_SAFETY,EMERGENCY - burst / flood / leak + ceiling →
PLUMBING,URGENT - no hot water / cold shower →
PLUMBING,URGENT - power out / no electricity →
ELECTRICAL,URGENT - oven / fridge / washing machine →
APPLIANCE,NORMAL - lock / key / break-in →
SECURITY,URGENT - …and so on. Not as nuanced, but never returns nothing.
Implementation: HeuristicTriageAssistant in
backend/modules/infrastructure. Rules live as plain Java so they're
code-reviewed alongside everything else.
API
POST /api/v1/maintenance-requests/{id}/suggest-triage
No body. Returns the triage JSON above. Idempotent — re-calling returns a fresh suggestion each time; nothing is written until you apply.
POST /api/v1/maintenance-requests/{id}/apply-triage
Content-Type: application/json
{
"category": "EMERGENCY_SAFETY",
"urgency": "EMERGENCY"
}
Writes the triage decision, transitions status to TRIAGED, starts the
SLA timer, writes an audit-log row.
Privacy
Only the tenant's report text is sent to Anthropic for triage. No tenant name, no email, no address, no property identifier. See AI Privacy & Fallbacks for the full list of what we do and don't transmit.
See also
- Duplicate Detection — runs before or after triage
- Convert to Work Order — the next step
- AI Triage (deep dive) — prompt version history + evaluation methodology