Spaces:
Sleeping
Sleeping
File size: 23,586 Bytes
1099afe 522f7a0 1099afe 522f7a0 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 |
# DEPENDENCIES
from enum import Enum
from typing import Dict
from typing import List
from typing import Tuple
class ContractType(Enum):
EMPLOYMENT = "employment"
CONSULTING = "consulting"
NDA = "nda"
SOFTWARE = "software"
SERVICE = "service"
PARTNERSHIP = "partnership"
LEASE = "lease"
PURCHASE = "purchase"
GENERAL = "general"
class RiskRules:
"""
Comprehensive risk scoring rules for broad contract coverage
"""
CATEGORY_WEIGHTS = {"restrictive_covenants" : 15,
"termination_rights" : 12,
"penalties_liability" : 14,
"compensation_benefits" : 13,
"intellectual_property" : 12,
"confidentiality" : 10,
"liability_indemnity" : 11,
"governing_law" : 8,
"payment_terms" : 10,
"warranties" : 9,
"dispute_resolution" : 7,
"assignment_change" : 6,
"insurance" : 5,
"force_majeure" : 4,
}
# Contract-specific weight adjustments
CONTRACT_TYPE_ADJUSTMENTS = {ContractType.EMPLOYMENT : {"restrictive_covenants": 1.8, "compensation_benefits": 1.6, "termination_rights": 1.4, "confidentiality": 1.3},
ContractType.SOFTWARE : {"intellectual_property": 1.8, "penalties_liability": 1.5, "warranties": 1.4, "payment_terms": 1.3},
ContractType.NDA : {"confidentiality": 2.0, "penalties_liability": 1.6, "restrictive_covenants": 1.4},
ContractType.CONSULTING : {"compensation_benefits": 1.5, "termination_rights": 1.3, "liability_indemnity": 1.4},
ContractType.LEASE : {"payment_terms": 1.6, "termination_rights": 1.5, "liability_indemnity": 1.4},
ContractType.PURCHASE : {"warranties": 1.7, "payment_terms": 1.5, "liability_indemnity": 1.3},
ContractType.PARTNERSHIP : {"governing_law": 1.6, "dispute_resolution": 1.5, "assignment_change": 1.4},
ContractType.SERVICE : {"payment_terms": 1.5, "warranties": 1.4, "termination_rights": 1.3},
}
CRITICAL_KEYWORDS = {"non-compete" : 25,
"non-solicit" : 23,
"non-solicitation" : 23,
"forfeit" : 25,
"liquidated damages" : 24,
"wage withholding" : 25,
"unlimited liability" : 25,
"joint and several" : 23,
"perpetual" : 22,
"irrevocable" : 20,
"automatic renewal" : 21,
"assignment without consent" : 22,
"sole discretion" : 23,
}
HIGH_RISK_KEYWORDS = {"indemnify" : 18,
"indemnification" : 18,
"hold harmless" : 17,
"penalty" : 18,
"damages" : 15,
"breach" : 15,
"default" : 14,
"immediate termination" : 16,
"without cause" : 15,
"at-will" : 14,
"waive" : 16,
"release" : 15,
"confidential" : 12,
"proprietary" : 12,
"exclusive" : 14,
"non-refundable" : 16,
}
MEDIUM_RISK_KEYWORDS = {"terminate" : 7,
"termination" : 7,
"assignment" : 6,
"warranty" : 8,
"representation" : 7,
"covenant" : 8,
"jurisdiction" : 6,
"governing law" : 6,
"insurance" : 5,
"force majeure" : 4,
"amendment" : 5,
"notice" : 4,
}
RISKY_PATTERNS = [(r'\d+\s*(year|yr|month|mo)s?\s*(non-compete|non-solicit)', 20, "Long duration restrictive covenant"),
(r'(entire|all|worldwide|global)\s*(industry|market|territory)', 18, "Overly broad geographic/industry scope"),
(r'notice\s+period.*\d+\s*days.*employee.*\d+\s*days.*employer', 15, "Unequal notice periods"),
(r'(may|can|shall)\s+(withhold|deduct|retain).*compensation', 22, "Wage withholding clause"),
(r'(unlimited|no\s+limit|without\s+limitation).*liability', 25, "Unlimited liability exposure"),
(r'(sole|absolute|unfettered)\s+discretion', 18, "One-sided discretionary power"),
(r'penalty.*(?:equal\s+to|of|amount).*\$?\d+', 16, "Specific penalty amount"),
(r'(automatically|immediately)\s+(renew|extend)', 12, "Auto-renewal clause"),
(r'waive.*right.*arbitration', 20, "Arbitration rights waiver"),
(r'(all|any).*intellectual\s+property.*created', 17, "Broad IP assignment"),
(r'payment.*due.*upon.*signature', 14, "Payment due upon signature"),
(r'no.*warranty.*(?:merchantability|fitness)', 15, "No warranty disclaimer"),
(r'governing\s+law.*\b(?:delaware|nevada)\b', 8, "Specific governing law"),
]
CLAUSE_RISK_FACTORS = {"non_compete" : {"base_risk" : 70,
"red_flags" : {"same industry": 0, "direct competitor": -5, "entire industry": +20, "all industries": +25, "worldwide": +15, "global": +15, "specific city": -10, "specific state": -5},
},
"termination" : {"base_risk" : 50,
"red_flags" : {"without cause": +15, "immediate": +12, "at will": +10, "sole discretion": +18, "no notice": +20, "no reason": +15},
},
"indemnification" : {"base_risk" : 60,
"red_flags" : {"unlimited": +25, "joint and several": +20, "gross negligence": -10, "willful misconduct": -10, "third party": +8, "all claims": +15, "any claims": +15},
},
"compensation" : {"base_risk" : 30,
"red_flags" : {"to be determined": +20, "tbd": +20, "subject to review": +15, "discretionary": +18, "at employer's discretion": +22, "may withhold": +25, "can deduct": +20},
},
"intellectual_property" : {"base_risk" : 55,
"red_flags" : {"all work product": +18, "anything created": +20, "during employment": +10, "after employment": +25, "including personal projects": +30, "whether or not related": +25},
},
"confidentiality" : {"base_risk" : 45,
"red_flags" : {"perpetual": +20, "indefinite": +18, "all information": +15, "including public information": +25},
},
"payment" : {"base_risk" : 35,
"red_flags" : {"net 90": +15, "net 120": +20, "upon completion": +10, "discretionary": +18},
},
"warranty" : {"base_risk" : 40,
"red_flags" : {"as is": +25, "no warranty": +20, "disclaims all": +22},
},
}
INDUSTRY_BENCHMARKS = {"non_compete_duration" : {"tech" : {"reasonable": 6, "standard": 12, "excessive": 24},
"finance" : {"reasonable": 12, "standard": 18, "excessive": 36},
"healthcare" : {"reasonable": 12, "standard": 24, "excessive": 36},
"general" : {"reasonable": 6, "standard": 12, "excessive": 24},
},
"notice_period_days" : {"executive" : {"reasonable": 90, "standard": 60, "minimal": 30},
"senior" : {"reasonable": 60, "standard": 30, "minimal": 14},
"professional" : {"reasonable": 30, "standard": 14, "minimal": 7},
"general" : {"reasonable": 30, "standard": 14, "minimal": 7},
},
"liability_cap_multiplier" : {"saas" : {"generous": 24, "standard": 12, "restrictive": 3},
"consulting" : {"generous": 3, "standard": 1, "restrictive": 0.5},
"general" : {"generous": 12, "standard": 6, "restrictive": 1},
},
}
PROTECTION_CHECKLIST = {"for_cause_definition" : {"importance": "critical", "risk_if_missing": 25, "categories": ["termination_rights"]},
"severance_provision" : {"importance": "high", "risk_if_missing": 18, "categories": ["termination_rights", "compensation_benefits"]},
"mutual_indemnification" : {"importance": "high", "risk_if_missing": 20, "categories": ["liability_indemnity"]},
"liability_cap" : {"importance": "critical", "risk_if_missing": 25, "categories": ["liability_indemnity", "penalties_liability"]},
"prior_ip_exclusion" : {"importance": "high", "risk_if_missing": 22, "categories": ["intellectual_property"]},
"confidentiality_duration" : {"importance": "medium", "risk_if_missing": 12, "categories": ["confidentiality"]},
"dispute_resolution" : {"importance": "medium", "risk_if_missing": 15, "categories": ["dispute_resolution"]},
"change_control_process" : {"importance": "medium", "risk_if_missing": 10, "categories": ["assignment_change"]},
"insurance_requirements" : {"importance": "medium", "risk_if_missing": 12, "categories": ["insurance"]},
"force_majeure" : {"importance": "low", "risk_if_missing": 8, "categories": ["force_majeure"]},
}
RISK_THRESHOLDS = {"critical" : 80,
"high" : 60,
"medium" : 40,
"low" : 20,
}
CATEGORY_DESCRIPTIONS = {"restrictive_covenants" : {"high" : "Overly restrictive non-compete, non-solicit, or confidentiality terms that may significantly limit future opportunities",
"medium" : "Some restrictive terms present; review duration, geographic scope, and industry limitations",
"low" : "Reasonable restrictive covenants appropriate for this role and industry standards",
},
"termination_rights" : {"high" : "Unbalanced termination rights with immediate termination, 'at-will' clauses, or unequal notice periods favoring one party",
"medium" : "Moderately balanced termination provisions; review notice period requirements and severance terms",
"low" : "Fair termination rights with reasonable notice periods and balanced severance provisions",
},
"penalties_liability" : {"high" : "Excessive penalty clauses, unlimited liability exposure, or one-sided indemnification terms",
"medium" : "Some concerning liability terms; review indemnification scope, damage limitations, and warranty provisions",
"low" : "Standard liability limitations, reasonable penalty provisions, and balanced indemnification terms",
},
"compensation_benefits" : {"high" : "Compensation structure lacks clarity, contains vague terms, or has unfavorable payment conditions",
"medium" : "Compensation terms are generally clear but could benefit from more specific bonus structure and payment terms",
"low" : "Clear and competitive compensation package with well-defined payment terms and bonus structure",
},
"intellectual_property" : {"high" : "Overly broad IP assignment that may cover personal projects or lacks proper prior IP exclusion",
"medium" : "IP terms mostly clear but could benefit from stronger prior IP protection and clearer ownership terms",
"low" : "Well-defined intellectual property ownership, clear usage rights, and proper prior IP exclusion",
},
"confidentiality" : {"high" : "Overly broad confidentiality scope, perpetual duration, or insufficient protection exceptions",
"medium" : "Standard confidentiality terms with some areas that could be more precisely defined",
"low" : "Reasonable confidentiality provisions with appropriate scope and duration",
},
"liability_indemnity" : {"high" : "Unbalanced indemnification, unlimited liability exposure, or insufficient liability caps",
"medium" : "Moderate liability terms; review indemnification mutuality and liability limitations",
"low" : "Balanced indemnification provisions with reasonable liability limitations",
},
"governing_law" : {"high" : "Unfavorable jurisdiction selection, one-sided dispute resolution, or restrictive venue requirements",
"medium" : "Standard governing law terms with generally acceptable jurisdiction and dispute resolution",
"low" : "Reasonable governing law and jurisdiction provisions favorable to both parties",
},
"payment_terms" : {"high" : "Unfavorable payment terms, extended payment periods, or unclear payment conditions",
"medium" : "Standard payment terms with some areas that could be improved for cash flow",
"low" : "Favorable payment terms with reasonable payment periods and clear conditions",
},
"warranties" : {"high" : "Overly broad warranty disclaimers, insufficient product guarantees, or one-sided warranty terms",
"medium" : "Standard warranty provisions with typical product/service guarantees",
"low" : "Comprehensive warranty coverage with reasonable limitations and clear guarantees",
},
"dispute_resolution" : {"high" : "Unfavorable dispute resolution process, restrictive arbitration clauses, or one-sided legal fee allocation",
"medium" : "Standard dispute resolution terms with generally fair arbitration or litigation process",
"low" : "Reasonable dispute resolution process with fair arbitration and cost allocation",
},
"assignment_change" : {"high" : "Restrictive assignment clauses, one-sided change control, or unfavorable amendment procedures",
"medium" : "Standard assignment and change control terms with reasonable flexibility",
"low" : "Reasonable assignment rights and change control processes favorable to both parties",
},
"insurance" : {"high" : "Insufficient insurance requirements, unclear coverage terms, or inadequate policy specifications",
"medium" : "Standard insurance requirements with typical coverage expectations",
"low" : "Comprehensive insurance requirements with clear coverage specifications",
},
"force_majeure" : {"high" : "Overly narrow force majeure definition, insufficient relief provisions, or one-sided termination rights",
"medium" : "Standard force majeure clause with typical relief provisions",
"low" : "Comprehensive force majeure protection with reasonable relief and termination rights",
},
}
PROTECTION_NAME_MAP = {"for_cause_definition" : "For Cause Definition",
"severance_proportion" : "Severance Provision",
"mutual_indemnification" : "Mutual Indemnification",
"liability_cap" : "Liability Cap",
"prior_ip_exclusion" : "Prior IP Exclusion",
"confidentiality_duration" : "Confidentiality Duration Limit",
"dispute_resolution" : "Dispute Resolution Process",
"change_control_process" : "Change Control Process",
"insurance_requirements" : "Insurance Requirements",
"force_majeure" : "Force Majeure Protection",
}
@classmethod
def get_adjusted_weights(cls, contract_type: ContractType) -> Dict[str, float]:
"""
Get category weights adjusted for contract type
"""
base_weights = cls.CATEGORY_WEIGHTS.copy()
adjustments = cls.CONTRACT_TYPE_ADJUSTMENTS.get(contract_type, {})
adjusted = dict()
for category, weight in base_weights.items():
multiplier = adjustments.get(category, 1.0)
adjusted[category] = weight * multiplier
# Normalize to sum to 100
total = sum(adjusted.values())
adjusted_weights = {k: (v / total) * 100 for k, v in adjusted.items()}
return adjusted_weights
@classmethod
def get_category_description(cls, category: str, score: int) -> str:
"""
Get meaningful description for a category based on score
"""
if category not in cls.CATEGORY_DESCRIPTIONS:
return "Review recommended based on risk score"
if (score >= 70):
risk_level = "high"
elif (score >= 40):
risk_level = "medium"
else:
risk_level = "low"
category_description = cls.CATEGORY_DESCRIPTIONS[category][risk_level]
return category_description
@classmethod
def get_protection_display_name(cls, protection_id: str) -> str:
"""
Get the display name for a protection ID: Uses PROTECTION_NAME_MAP for known IDs, otherwise formats the ID
"""
return cls.PROTECTION_NAME_MAP.get(protection_id, protection_id.replace("_", " ").title())
|