Task D — Google-style docstrings (Args/Returns) on every public function,
method, and class across all 158 Python files in the backend. Zero ruff D
violations (pydocstyle Google convention).
Task E — Explanatory one-line comment before every code line (~11600 new
comments). ruff check passes clean after isort re-sort.
MITRE ATT&CK STIX data never includes primary_motivation on intrusion-set
objects. Motivation is now derived with a 3-tier fallback:
1. Curated MITRE-ID override map (100+ known groups mapped by hand)
2. STIX primary_motivation field (if MITRE ever adds it)
3. Description keyword inference (financ/ransomware/espionage/
nation-state/destructive/hacktivist patterns)
Re-running MITRE sync will now backfill motivation for existing actors.
1. fix(search 500): func.cast(col, func.text()) is invalid SQLAlchemy —
replaced with cast(col, Text) for both aliases and target_sectors
JSONB columns. Generating correct CAST(col AS TEXT) SQL.
2. feat(motivation): extract primary_motivation and sophistication from
STIX intrusion-set objects during MITRE sync. Added _normalize_motivation()
to map STIX vocabulary → simplified frontend values (espionage / financial /
destruction / hacktivism). Both create and update paths now set these fields.
Run MITRE sync to backfill existing actors.