Files
zeus-skills/ops/connectwise/connectwise-open-tickets-report/references/sla_evaluation.md
T

3.1 KiB

ConnectWise SLA Evaluation Recipe

Reference: sla_evaluation.md — How to evaluate SLA state and score tickets for prioritization using the CW v3 API.

Fields to Read

Field Type Meaning
isInSla bool False = breached
slaStatus string e.g. "Respond by Tue 04/21 3:37 PM UTC-07"
respondMinutes int Minutes in "respond" phase
resPlanMinutes int Minutes in "resplan" phase
resolveMinutes int Minutes in "resolve" phase
escalationLevel int Tier (higher = worse)
priority.level string Critical / High / Medium / Low
severity string Critical / High / Medium / Low
impact string Critical / High / Medium / Low
_info.dateEntered ISO string Canonical creation time

Composite Scoring Formula

score = 0

if sla_overdue:
    score += 1000
elif sla_state == 'Due <24h':
    score += 500
elif sla_state == 'Due <72h':
    score += 200

score += (escalation or 0) * 50

prio_map = {
    'Priority 1 - Critical': 400,
    'Priority 2 - High': 200,
    'Priority 3 - Medium': 50,
    'Priority 4 - Low': 10
}
score += prio_map.get(priority_name, 0)

if severity in ('Critical', 'High'):
    score += 100
if impact in ('Critical', 'High'):
    score += 100

if date_entered:
    age_days = (now - date_entered).total_seconds() / 86400
    score += min(int(age_days) * 5, 300)

SLA State Parsing

import re
from datetime import datetime

def parse_sla(sla_status_text):
    if not sla_status_text or sla_status_text == 'Resolved':
        return sla_status_text or 'No SLA'
    m = re.search(r'(Respond|Resolve)\s+by\s+(.+)', sla_status_text, re.IGNORECASE)
    if m:
        due_text = m.group(2).strip()
        try:
            dt = datetime.strptime(due_text, '%a %m/%d %I:%M %p %Z%z')
            if dt < now:
                return 'Overdue'
            hours = (dt - now).total_seconds() / 3600
            if hours < 24:
                return 'Due <24h'
            elif hours < 72:
                return 'Due <72h'
            return 'On Track'
        except ValueError:
            return 'Due (unparsed)'
    return sla_status_text

RMM Alert Categories (for filtering / triage)

Keyword-based categorization of common Sophos/RMM-generated summaries:

Category Keywords
Firewall Sophos Offline firewall + sophos
Firewall Heartbeat not sending heartbeat
Gateway Down gateway + down
Malware Detection malicious, c2/
Device Offline has not contacted
Disk/Storage disk, drive, storage, c:
CPU Alert cpu
Memory Alert memory, ram
Reboot Required reboot, restart
AV Alert antivirus, virus

Bulk Close Recipe

Update stale "new from RMM" tickets to "Self-Healed":

# 1. Fetch all open tickets
# 2. Filter: status == 'new from RMM' AND _info.dateEntered > 7 days ago
# 3. PATCH each: [{"op": "replace", "path": "/status/id", "value": 425}]
# Status ID 425 = "Self-Healed" on board 6 (Managed Service Alerts)

Never auto-close malware detections without human review.