Cookbook 323: Offline Clinical Rheumatology Systemic Sclerosis Rodnan & Renal Crisis Engine

This cookbook details how to deploy a localized, containerized rheumatology, clinical immunology, and pulmonary fibrosis decision-support engine for rheumatology clinics, autoimmune disease centers, and emergency departments to ingest autoimmune serologies, nailfold capillaroscopy patterns, pulmonary function tests ($\text{PFTs}$), high-resolution computed tomography ($\text{HRCT}$) lung fibrosis scores, and serial blood pressure telemetry, classify Systemic Sclerosis ($\text{SSc}$) under the ACR/EULAR 2013 Classification Criteria ($\text{Score} \ge 9$), quantify cutaneous fibrosis via the 17-site Modified Rodnan Skin Score ($\text{mRSS}$, $0 - 51\text{ points}$), stage SSc-Associated Interstitial Lung Disease ($\text{SSc-ILD}$) via the Goh / Wells algorithm ($\text{FVC}$ & $\text{HRCT}$ extent), and execute the life-saving Scleroderma Renal Crisis ($\text{SRC}$) Emergency Captopril Protocol while flagging high-dose corticosteroid contraindications according to ACR, EULAR, and Scleroderma Clinical Trials Consortium ($\text{SCTC}$) guidelines without external cloud API reliance.


1. Clinical Background & Autoimmune Architecture

Systemic sclerosis is a complex autoimmune connective tissue disease characterized by immune dysregulation, microvascular vasculopathy, and progressive tissue fibrosis across skin, lungs, gastrointestinal tract, and kidneys:


2. Pipeline & Workflow Architecture

[Rheumatology Telemetry: Serologies, Nailfold Capillaries, Raynaud's, Skin & Lung Exams]
                                         │
                                         ▼
      [ACR/EULAR 2013 Classifier: 8 Weighted Diagnostic Domains -> Total Score >= 9]
                                         │
                                         ▼
      [17-Site Modified Rodnan Skin Score (mRSS) Engine: Total 0-51 & Subtype Triage]
                                         │
                                         ▼
    [SSc-ILD Staging (Goh Criteria: HRCT Extent % + FVC % / DLCO % Pulmonary Function)]
                                         │
                                         ▼
    [Scleroderma Renal Crisis (SRC) Sentinel & Emergent Captopril Titration Protocol]

3. Environment & Prerequisites

Install required scientific Python and autoimmune disease modeling packages:

pip install numpy scipy pandas torch torchvision matplotlib

4. Complete Offline Python / PyTorch Implementation

"""
Cookbook 323: Offline Rheumatology Systemic Sclerosis Rodnan & Renal Crisis Engine
OpenPHR Clinical AI Working Group (https://openphr.org)
"""

import math
import numpy as np
import pandas as pd
from typing import Dict, List, Tuple, Optional
from dataclasses import dataclass, field

@dataclass
class SScClinicalTelemetry:
    patient_id: str
    age_years: float
    # ACR/EULAR 2013 Diagnostic Criteria Parameters
    skin_thickening_proximal_to_mcps: bool = False # 9 points (Sufficient on its own)
    skin_thickening_fingers_type: str = "Sclerodactyly" # "None" (0), "Puffy" (2), "Sclerodactyly" (4)
    fingertip_lesions_type: str = "Digital Tip Ulcers" # "None" (0), "Digital Tip Ulcers" (2), "Pitting Scars" (3)
    telangiectasia_present: bool = True # 2 points
    abnormal_nailfold_capillaries: bool = True # 2 points (Megacapillaries/loss)
    pulmonary_involvement_present: bool = True # 2 points (PAH or ILD)
    raynauds_phenomenon_present: bool = True # 3 points
    ssc_specific_autoantibodies_positive: bool = True # 3 points (ACA, Scl-70, or RNA Pol III)
    positive_autoantibody_name: str = "Anti-RNA Polymerase III (High SRC Risk)"
    # 17-Site Modified Rodnan Skin Score (mRSS) Telemetry (0 to 3 per site)
    mrss_face: int = 1
    mrss_chest: int = 2
    mrss_abdomen: int = 2
    mrss_r_upper_arm: int = 2
    mrss_l_upper_arm: int = 2
    mrss_r_forearm: int = 3
    mrss_l_forearm: int = 3
    mrss_r_hand: int = 2
    mrss_l_hand: int = 2
    mrss_r_fingers: int = 3
    mrss_l_fingers: int = 3
    mrss_r_thigh: int = 1
    mrss_l_thigh: int = 1
    mrss_r_lower_leg: int = 2
    mrss_l_lower_leg: int = 2
    mrss_r_foot: int = 1
    mrss_l_foot: int = 1
    # Pulmonary Function & HRCT Telemetry
    hrct_lung_fibrosis_extent_percent: float = 24.0 # % (> 20% = Extensive ILD)
    fvc_percent_predicted: float = 64.0 # % (< 70% with indeterminate HRCT = Extensive)
    dlco_percent_predicted: float = 52.0 # %
    # Scleroderma Renal Crisis (SRC) Hemodynamic & Medication Telemetry
    systolic_bp_mmhg: float = 178.0 # mmHg (>= 140 or acute rise)
    diastolic_bp_mmhg: float = 104.0 # mmHg
    baseline_serum_creatinine_mg_dl: float = 0.9 # mg/dL
    current_serum_creatinine_mg_dl: float = 2.4 # mg/dL (Acute >50% rise)
    schistocytes_present_on_smear: bool = True # Microangiopathic hemolytic anemia
    platelet_count_k_ul: float = 88.0 # Thrombocytopenia (< 150 k/uL)
    current_prednisone_dose_mg_day: float = 20.0 # mg/day (>= 15 mg = High SRC trigger!)

@dataclass
class SScEvaluationReport:
    patient_id: str
    acr_eular_total_score: int
    classification_status: str # "Definite Systemic Sclerosis (ACR/EULAR Score >= 9)", "Not Classified"
    criteria_breakdown: List[str]
    total_mrss_score: int # 0 - 51
    cutaneous_subtype: str # "Diffuse Cutaneous Systemic Sclerosis (dcSSc)", "Limited Cutaneous SSc (lcSSc)"
    ssc_ild_stage: str # "Extensive / Severe SSc-ILD", "Limited SSc-ILD", "No ILD"
    src_crisis_status: str # "🚨 ACUTE SCLERODERMA RENAL CRISIS (SRC)", "No Renal Crisis"
    emergency_captopril_protocol: List[str]
    safety_sentinels: List[str]
    clinical_guideline_directive: str

class SystemicSclerosisDecisionEngine:
    """
    Offline clinical engine for ACR/EULAR 2013 Systemic Sclerosis classification,
    Modified Rodnan Skin Score (mRSS) assessment, SSc-ILD staging, and Scleroderma
    Renal Crisis (SRC) emergency triage.
    """

    def calculate_acr_eular_score(self, d: SScClinicalTelemetry) -> Tuple[int, str, List[str]]:
        score = 0
        breakdown = []

        # Criterion 1: Skin thickening proximal to MCPs (9 pts - Standalone)
        if d.skin_thickening_proximal_to_mcps:
            score = 9
            breakdown.append("Skin thickening of fingers extending proximal to MCP joints (9 points - Standalone Definitive Criterion).")
            return 9, "Definite Systemic Sclerosis (ACR/EULAR Criteria Met)", breakdown

        # Criterion 2: Skin thickening of fingers
        if d.skin_thickening_fingers_type == "Sclerodactyly":
            score += 4
            breakdown.append("Sclerodactyly of fingers distal to MCPs (4 points).")
        elif d.skin_thickening_fingers_type == "Puffy":
            score += 2
            breakdown.append("Puffy fingers (2 points).")

        # Criterion 3: Fingertip lesions
        if d.fingertip_lesions_type == "Pitting Scars":
            score += 3
            breakdown.append("Digital fingertip pitting scars (3 points).")
        elif d.fingertip_lesions_type == "Digital Tip Ulcers":
            score += 2
            breakdown.append("Digital fingertip ulcers (2 points).")

        # Criterion 4: Telangiectasia
        if d.telangiectasia_present:
            score += 2
            breakdown.append("Telangiectasia (2 points).")

        # Criterion 5: Abnormal nailfold capillaries
        if d.abnormal_nailfold_capillaries:
            score += 2
            breakdown.append("Abnormal nailfold capillaries (2 points).")

        # Criterion 6: Pulmonary involvement (PAH / ILD)
        if d.pulmonary_involvement_present:
            score += 2
            breakdown.append("Pulmonary arterial hypertension and/or Interstitial lung disease (2 points).")

        # Criterion 7: Raynaud's phenomenon
        if d.raynauds_phenomenon_present:
            score += 3
            breakdown.append("Raynaud's phenomenon (3 points).")

        # Criterion 8: SSc-specific autoantibodies
        if d.ssc_specific_autoantibodies_positive:
            score += 3
            breakdown.append(f"SSc-specific autoantibodies positive ({d.positive_autoantibody_name}) (3 points).")

        status = "Definite Systemic Sclerosis (ACR/EULAR Score >= 9)" if score >= 9 else f"Unclassified / Borderline SSc (Score {score} < 9)"
        return score, status, breakdown

    def compute_mrss_and_subtype(self, d: SScClinicalTelemetry) -> Tuple[int, str]:
        mrss_total = (
            d.mrss_face + d.mrss_chest + d.mrss_abdomen +
            d.mrss_r_upper_arm + d.mrss_l_upper_arm +
            d.mrss_r_forearm + d.mrss_l_forearm +
            d.mrss_r_hand + d.mrss_l_hand +
            d.mrss_r_fingers + d.mrss_l_fingers +
            d.mrss_r_thigh + d.mrss_l_thigh +
            d.mrss_r_lower_leg + d.mrss_l_lower_leg +
            d.mrss_r_foot + d.mrss_l_foot
        )

        # Diffuse vs Limited Subtype:
        # Diffuse has skin thickening proximal to elbows/knees or trunk (chest/abdomen/thighs/upper arms)
        has_proximal_involvement = (
            d.mrss_chest > 0 or d.mrss_abdomen > 0 or
            d.mrss_r_upper_arm > 0 or d.mrss_l_upper_arm > 0 or
            d.mrss_r_thigh > 0 or d.mrss_l_thigh > 0
        )

        subtype = "Diffuse Cutaneous Systemic Sclerosis (dcSSc)" if has_proximal_involvement else "Limited Cutaneous Systemic Sclerosis (lcSSc)"
        return mrss_total, subtype

    def stage_ssc_ild(self, d: SScClinicalTelemetry) -> Tuple[str, str]:
        # Goh / Wells Criteria:
        # Extensive: HRCT > 20% OR (HRCT 10-30% with FVC < 70%)
        # Limited: HRCT < 20% OR (HRCT 10-30% with FVC >= 70%)
        if d.hrct_lung_fibrosis_extent_percent > 20.0 or (d.hrct_lung_fibrosis_extent_percent >= 10.0 and d.fvc_percent_predicted < 70.0):
            stage = "Extensive / Severe SSc-ILD (High Risk for Progressive Fibrosis)"
            tx = "Initiate immunosuppression: Mycophenolate Mofetil (MMF target 2-3 g/day) +/- Nintedanib antifibrotic (150 mg BID) or Tocilizumab."
        elif d.hrct_lung_fibrosis_extent_percent > 0.0:
            stage = "Limited SSc-ILD (Mild-to-Moderate)"
            tx = "Close serial surveillance: PFTs (FVC/DLCO) every 3-6 months. Consider MMF if active decline in FVC >= 10% or DLCO >= 15%."
        else:
            stage = "No SSc-ILD Detected"
            tx = "Annual PFT screening and clinical pulmonary monitoring."

        return stage, tx

    def evaluate_src_renal_crisis(self, d: SScClinicalTelemetry) -> Tuple[str, List[str], List[str]]:
        src_triggers = []
        captopril_orders = []
        sentinels = []

        # Hypertension check
        is_hypertensive = d.systolic_bp_mmhg >= 140.0 or d.diastolic_bp_mmhg >= 90.0
        # Creatinine rise check (> 50% rise over baseline)
        scr_rise_ratio = d.current_serum_creatinine_mg_dl / max(d.baseline_serum_creatinine_mg_dl, 0.1)
        has_renal_impairment = scr_rise_ratio >= 1.5

        if is_hypertensive and (has_renal_impairment or d.schistocytes_present_on_smear or "RNA Polymerase" in d.positive_autoantibody_name):
            crisis_status = "🚨 ACUTE SCLERODERMA RENAL CRISIS (SRC) - MEDICAL EMERGENCY"
            src_triggers.append(f"Accelerated Hypertension: {d.systolic_bp_mmhg:.0f}/{d.diastolic_bp_mmhg:.0f} mmHg.")
            src_triggers.append(f"Acute Kidney Injury: SCr rise from {d.baseline_serum_creatinine_mg_dl:.1f} to {d.current_serum_creatinine_mg_dl:.1f} mg/dL ({scr_rise_ratio:.1f}x baseline).")
            if d.schistocytes_present_on_smear:
                src_triggers.append("Microangiopathic Hemolytic Anemia (MAHA): Schistocytes and Thrombocytopenia present.")

            # Emergency Captopril Orders
            captopril_orders.append("1. STAT INGESTION: Administer Captopril 6.25 - 12.5 mg PO test dose immediately.")
            captopril_orders.append("2. TITRATION: Repeat Captopril 12.5 - 25 mg every 4-6 hours, titrating rapidly to 50 - 100 mg PO TID.")
            captopril_orders.append("3. BLOOD PRESSURE TARGET: Aim for SBP reduction of 10 - 20 mmHg per 24 hours down to patient's normal baseline (Avoid precipitous drops to prevent ischemic stroke/renal infarction).")
            captopril_orders.append("4. PERMISSIVE CREATININEMIA: Do NOT stop Captopril if serum creatinine rises further during initial days; renal recovery follows normalization of blood pressure.")
            captopril_orders.append("5. SECOND-LINE AGENTS: If BP refractory to max Captopril, add Calcium Channel Blocker (Nifedipine) or IV Prostacyclin (Iloprost). Avoid ARBs as first-line.")
        else:
            crisis_status = "No Scleroderma Renal Crisis Detected"

        # Steroid Danger Sentinel
        if d.current_prednisone_dose_mg_day >= 15.0:
            sentinels.append(f"CRITICAL STEROID CONTRAINDICATION: Current Prednisone dose ({d.current_prednisone_dose_mg_day:.0f} mg/day) >= 15 mg/day is a potent precipitator of Scleroderma Renal Crisis (SRC). Taper corticosteroids immediately below 10-15 mg/day unless strictly mandatory for myositis or pericarditis.")

        if "RNA Polymerase" in d.positive_autoantibody_name:
            sentinels.append("HIGH-RISK SEROLOGY: Anti-RNA Polymerase III positivity carries a ~30% lifetime incidence of SRC. Enforce daily home blood pressure monitoring (Report SBP >= 140 or acute rise >= 20 mmHg).")

        return crisis_status, captopril_orders, sentinels

    def evaluate_case(self, data: SScClinicalTelemetry) -> SScEvaluationReport:
        acr_score, class_status, criteria = self.calculate_acr_eular_score(data)
        mrss_total, subtype = self.compute_mrss_and_subtype(data)
        ild_stage, ild_tx = self.stage_ssc_ild(data)
        src_status, captopril_plan, sentinels = self.evaluate_src_renal_crisis(data)

        directives = []
        directives.append(f"CLASSIFICATION: {class_status} (Score {acr_score}/9).")
        directives.append(f"SUBTYPE: {subtype} with mRSS {mrss_total}/51.")
        directives.append(f"PULMONARY: {ild_stage}. {ild_tx}")
        directives.append(f"RENAL STATUS: {src_status}.")

        return SScEvaluationReport(
            patient_id=data.patient_id,
            acr_eular_total_score=acr_score,
            classification_status=class_status,
            criteria_breakdown=criteria,
            total_mrss_score=mrss_total,
            cutaneous_subtype=subtype,
            ssc_ild_stage=ild_stage,
            src_crisis_status=src_status,
            emergency_captopril_protocol=captopril_plan,
            safety_sentinels=sentinels,
            clinical_guideline_directive=" ".join(directives)
        )

# Example Execution & Verification
if __name__ == "__main__":
    engine = SystemicSclerosisDecisionEngine()

    print("=" * 80)
    print("OpenPHR Clinical Rheumatology Systemic Sclerosis & Renal Crisis Engine")
    print("=" * 80)

    # Test Case 1: 52-year-old female with Diffuse Cutaneous Systemic Sclerosis,
    # Anti-RNA Polymerase III positivity, SSc-ILD (HRCT 24%), and presenting with
    # Acute Scleroderma Renal Crisis (BP 178/104 mmHg, SCr 2.4 mg/dL, Schistocytes).
    # Trigger: Emergent Captopril Protocol & Prednisone 20 mg Warning Sentinel!
    ssc1 = SScClinicalTelemetry(
        patient_id="RHEUM-SSC-4409",
        age_years=52.0,
        skin_thickening_proximal_to_mcps=False,
        skin_thickening_fingers_type="Sclerodactyly",
        fingertip_lesions_type="Digital Tip Ulcers",
        telangiectasia_present=True,
        abnormal_nailfold_capillaries=True,
        pulmonary_involvement_present=True,
        raynauds_phenomenon_present=True,
        ssc_specific_autoantibodies_positive=True,
        positive_autoantibody_name="Anti-RNA Polymerase III",
        mrss_face=1, mrss_chest=2, mrss_abdomen=2,
        mrss_r_upper_arm=2, mrss_l_upper_arm=2,
        mrss_r_forearm=3, mrss_l_forearm=3,
        mrss_r_hand=2, mrss_l_hand=2,
        mrss_r_fingers=3, mrss_l_fingers=3,
        mrss_r_thigh=1, mrss_l_thigh=1,
        mrss_r_lower_leg=2, mrss_l_lower_leg=2,
        mrss_r_foot=1, mrss_l_foot=1,
        hrct_lung_fibrosis_extent_percent=24.0,
        fvc_percent_predicted=64.0,
        dlco_percent_predicted=52.0,
        systolic_bp_mmhg=178.0,
        diastolic_bp_mmhg=104.0,
        baseline_serum_creatinine_mg_dl=0.9,
        current_serum_creatinine_mg_dl=2.4,
        schistocytes_present_on_smear=True,
        platelet_count_k_ul=88.0,
        current_prednisone_dose_mg_day=20.0
    )

    rep1 = engine.evaluate_case(ssc1)

    print(f"\n[Patient {rep1.patient_id} - Rheumatology Assessment]")
    print(f"ACR/EULAR Classification: {rep1.classification_status} (Score: {rep1.acr_eular_total_score})")
    print("Criteria Breakdown:")
    for c in rep1.criteria_breakdown:
        print(f"  • {c}")
    print(f"\nCutaneous Subtype: {rep1.cutaneous_subtype} (mRSS Total: {rep1.total_mrss_score}/51)")
    print(f"Pulmonary Status: {rep1.ssc_ild_stage}")
    print(f"Renal Crisis Status: {rep1.src_crisis_status}")
    if rep1.emergency_captopril_protocol:
        print("\nEmergency Captopril Protocol:")
        for step in rep1.emergency_captopril_protocol:
            print(f"  {step}")
    if rep1.safety_sentinels:
        print("\nSafety Sentinels:")
        for s in rep1.safety_sentinels:
            print(f"  🚨 {s}")
    print(f"\nGuideline Directive:\n{rep1.clinical_guideline_directive}")

5. Clinical Verification & Guideline Conformance


6. References