diff --git a/src/psyc/cockpit/app.py b/src/psyc/cockpit/app.py index 0d8f843..c2193c3 100644 --- a/src/psyc/cockpit/app.py +++ b/src/psyc/cockpit/app.py @@ -77,7 +77,12 @@ def case_journey(request: Request, case_id: str) -> HTMLResponse: if isinstance(result, Err): raise HTTPException(status_code=404, detail=result.reason) beats = journey_view.build_journey(result.value) - return TEMPLATES.TemplateResponse(request, "journey.html", {"case": result.value, "beats": beats}) + model_label = inference.adapter_name() or "rules" + return TEMPLATES.TemplateResponse( + request, + "journey.html", + {"case": result.value, "beats": beats, "model_label": model_label}, + ) @app.get("/ledger", response_class=HTMLResponse) diff --git a/src/psyc/cockpit/inference.py b/src/psyc/cockpit/inference.py index e0d993f..2a47acf 100644 --- a/src/psyc/cockpit/inference.py +++ b/src/psyc/cockpit/inference.py @@ -34,6 +34,15 @@ def server_adapter(timeout: float = 2.0) -> Optional[str]: return None +def adapter_name(timeout: float = 2.0) -> Optional[str]: + """Short name of the live adapter, e.g. 'psyc-v5' from '/data/adapters/psyc-v5/final'.""" + path = server_adapter(timeout=timeout) + if not path: + return None + parts = [p for p in path.split("/") if p and p != "final"] + return parts[-1] if parts else None + + def model_severity(case: Case, timeout: float = 15.0) -> Optional[str]: """Ask the live model to classify case severity. None if the server is down.""" payload = { diff --git a/src/psyc/cockpit/templates/cases.html b/src/psyc/cockpit/templates/cases.html index 7e4152e..2338410 100644 --- a/src/psyc/cockpit/templates/cases.html +++ b/src/psyc/cockpit/templates/cases.html @@ -6,12 +6,12 @@
Every threat case psyc is tracking — ingested from URLhaus, CISA KEV, and Feodo Tracker, then classified by severity and TLP. The live queue of what the platform currently knows about; click any case to follow it through the pipeline.
+Every threat case psyc is tracking — ingested from URLhaus, CISA KEV, Feodo Tracker, ThreatFox, MalwareBazaar, and AlienVault OTX, then classified by severity and TLP. The live queue of what the platform currently knows about; click any case to follow it through the pipeline.
How to use. Scan the severity and TLP badges to triage; click any case ID to open its full record and Worker Mesh journey. Run psyc fetch-all to pull fresh cases from the feeds.
What you're seeing. Each row is one normalized Case object — ingested by Scoutline from URLhaus, CISA KEV, or Feodo Tracker, then rated by Classifyline.
+What you're seeing. Each row is one normalized Case object — ingested by Scoutline from any of six feeds (URLhaus, CISA KEV, Feodo Tracker, ThreatFox, MalwareBazaar, OTX), then rated by Classifyline.
Why it matters. A defender needs one place that answers "what is happening right now" before deciding what to act on — this queue is that place.
- ⬡ psyc-v4 · live model + ⬡ {{ model_label }} · live model severity: {{ b.model_answer | upper }} {% if agrees %}✓ agrees with the rule {% else %}✗ differs — rule said {{ rule_sev | upper }}{% endif %}