# Risk combination config — EDIT THIS to tune the tool.
#
# Combination is NOISY-OR (see risk.py): each signal votes = reliability * score,
# and risk = 1 - product(1 - vote). Any one confident signal can drive risk high.

# Per-attribute weights -> normalized by the max weight below, then scaled by
# attribute_reliability_ceiling to give each attribute's reliability (0..1).
# Grounded in Step-2 lift + Step-4 validation: financial/credential/reward
# validated strongest; grammar & caps_tone are UNRELIABLE ON THIS CORPUS
# (grammar flags corporate jargon; caps_tone doesn't separate) -> kept for
# real-world value + interpretability but deliberately low reliability.
attribute_weights:
  urgency: 1.0
  fear_threat: 1.1
  reward: 1.0
  curiosity: 0.5
  authority: 0.9
  financial: 1.5
  credential: 1.6
  generic_greeting: 0.9
  sender_domain: 1.3
  links: 1.2
  grammar: 0.35        # unreliable here (corporate-jargon false positives)
  caps_tone: 0.5       # non-discriminative here
  # Real-world detectors (headers/HTML/attachments). High-signal in the wild; the
  # 0.6 reliability ceiling still keeps any single one below a phishing verdict.
  sender_auth: 1.5     # SPF/DKIM/DMARC fail + From/Reply-To misalignment
  link_deception: 1.4  # anchor-vs-href mismatch, punycode/homograph, brand-in-subdomain
  obfuscation: 1.2     # hidden chars / homoglyph evasion
  attachment_risk: 1.3 # dangerous types / double extensions / macro docs
  bec: 1.3             # business email compromise (no-link wire/gift-card fraud)
  html_attack: 1.4     # credential-harvest forms / tracking beacons in the HTML
  # SCORING (not report_only): fires only on the specific abuse pattern (a
  # third-party credential/login link hosted on trusted SaaS - Google Forms,
  # DocuSign, *.web.app, ...). Weight kept <= the max scoring weight (credential
  # 1.6) so max_w is unchanged and every other attribute's balance is untouched.
  saas_abuse: 1.4

# A SINGLE rule attribute should top out at "suspicious", not "phishing": only
# the classifier (or several corroborating attributes) can reach a phishing
# verdict. So the top-weighted attribute (credential) reaches only this
# reliability; others scale below it. This keeps legit corporate mail that uses
# financial/authority vocabulary from being single-handedly flagged.
attribute_reliability_ceiling: 0.6

# Ignore attribute votes below this (reliability*score). Stops the always-firing
# weak attributes (caps_tone/grammar) from accumulating into false alarms.
vote_floor: 0.12

# The classifier is CO-EQUAL and, being a strong learned signal, is trusted enough
# to drive a verdict on its own. Dial DOWN if per-source metrics show it riding
# source/campaign leakage (Step-4 coefficient audit flagged 'enron'/'re:'/'thanks').
classifier_reliability: 0.97

# Verdict bands on the final 0..1 risk score. Recalibrated for noisy-OR (Step 4):
# confident-phishing now lands ~0.9+, benign corporate mail ~0.0-0.25.
verdict_thresholds:
  legitimate_below: 0.35        # < 0.35            -> "legitimate"
  phishing_at_or_above: 0.60    # >= 0.60           -> "phishing"; between -> "suspicious"

# Sender-trust discount (phishing_analyzer/trust.py): cut false positives on GENUINE
# bank / transactional mail whose wording overlaps with phishing. Only LOWERS risk,
# and only when the headers prove the message is authenticated (SPF/DKIM/DMARC pass)
# AND self-consistent (no link/attachment/obfuscation trickery). No headers -> no
# change, so body-only text keeps the original rule/ML balance.
sender_trust:
  enabled: true
  legitimate_cap: 0.2   # authenticated + consistent + (known brand / List-Unsubscribe / old domain)
  # Authenticated + consistent, but an UNKNOWN, unestablished domain. Set to 1.0 so the
  # cap never binds (pipeline.py only applies a cap when risk_score > cap), i.e. this tier
  # is inert: passing SPF/DKIM on a domain you registered yourself earns no discount.
  # Attackers routinely authenticate their own throwaway domains, and with the Gmail
  # extension now supplying real auth headers this tier would otherwise downgrade a
  # measured 0.99 credential lure to 0.5 ("suspicious" instead of "phishing"). The
  # trusted / established tiers above are unaffected and still clear genuine brand mail.
  suspicious_cap: 1.0
  # Established-domain trust: an authenticated email from a domain registered years
  # ago is a real organization (genuine verification/security/billing mail), so clear
  # it without an allowlist. Uses an RDAP lookup (Link X-ray), so it makes ONE network
  # call for an unknown authenticated sender; set false to keep the core fully offline.
  use_domain_age: true
  min_domain_age_days: 365

# Attributes excluded from the vote when uncomputable (e.g. sender_domain with no
# sender header) so absence of evidence isn't treated as evidence of safety.
skip_when_unavailable: [sender_domain, sender_auth, attachment_risk, html_attack]

# Detectors that are REPORTED in the output (attributes[]) for explainability but do
# NOT contribute to the risk score / verdict. This keeps the risk combination exactly
# as it was originally: the 12 language/heuristic attributes + the TF-IDF/LogReg
# classifier at their original balance. The real-world detectors surface as evidence
# without changing the score.
report_only: [sender_auth, link_deception, obfuscation, attachment_risk, bec, html_attack]
