Python Library Reference

Importing the Library

from si_protocols.threat_filter import hybrid_score, tech_analysis, ThreatResult
from si_protocols.markers import (
    VAGUE_ADJECTIVES,
    AUTHORITY_PHRASES,
    URGENCY_PATTERNS,
    FEAR_WORDS,
    EUPHORIA_WORDS,
    CONTRADICTION_PAIRS,
    UNFALSIFIABLE_SOURCE_PHRASES,
    COMMITMENT_ESCALATION_MARKERS,
)

hybrid_score()

The main entry point. Combines the NLP tech layer (60%) with the heuristic layer (40%) and returns a ThreatResult.

def hybrid_score(
    text: str,
    density_bias: float = 0.75,
    *,
    seed: int | None = None,
) -> ThreatResult

Parameters:

ParameterTypeDefaultDescription
textstr(required)The text to analyse
density_biasfloat0.75Information density bias for the heuristic layer (0.0–1.0). Lower values increase suspicion.
seedint | NoneNoneOptional RNG seed for the heuristic layer. Use a fixed seed for reproducible results.

Example:

from si_protocols.threat_filter import hybrid_score

text = open("examples/synthetic_suspicious.txt").read()
result = hybrid_score(text, seed=42)

print(f"Threat score: {result.overall_threat_score}/100")
print(f"Tech layer: {result.tech_contribution}")
print(f"Heuristic layer: {result.intuition_contribution}")
print(f"Authority claims: {result.authority_hits}")

tech_analysis()

Runs only the NLP tech layer, skipping the heuristic. Useful when you want deterministic results without a random seed.

def tech_analysis(
    text: str,
) -> tuple[float, list[str], list[str], list[str], list[str], list[str], list[str], list[str]]

Returns an 8-element tuple:

IndexValue
0Tech score (0–100)
1Detected named entities
2Authority claim hits
3Urgency pattern hits
4Emotion trigger hits
5Logical contradiction hits
6Source attribution hits
7Commitment escalation hits

Example:

from si_protocols.threat_filter import tech_analysis

score, entities, auth, urgency, emotion, contra, source, escalation = tech_analysis(text)
print(f"Tech score: {score}/100")

ThreatResult Fields

ThreatResult is a frozen dataclass returned by hybrid_score().

FieldTypeDescription
overall_threat_scorefloatHybrid score (0–100): 60% tech + 40% heuristic
tech_contributionfloatTech layer score (0–100)
intuition_contributionfloatHeuristic layer score
detected_entitieslist[str]Named entities found by spaCy
authority_hitslist[str]Matched authority claim phrases
urgency_hitslist[str]Matched urgency/fear patterns
emotion_hitslist[str]Matched fear and euphoria words/phrases
contradiction_hitslist[str]Labels of detected contradiction pairs
source_attribution_hitslist[str]Unfalsifiable and unnamed authority phrases
escalation_hitslist[str]Commitment escalation labels by segment
messagestrDisclaimer: “Run on your own texts only — this is a local tool.”

Scoring Dimensions

The tech layer scores text across seven independent dimensions, each normalised to 0–1 and combined with the following weights:

DimensionWeightWhat it detects
Vagueness17%Adjective density against VAGUE_ADJECTIVES
Authority claims17%Phrase matching against AUTHORITY_PHRASES
Urgency/fear13%Pattern matching against URGENCY_PATTERNS
Emotional manipulation13%Lemma-based fear/euphoria detection with a contrast bonus when both polarities appear
Logical contradictions13%Both poles of CONTRADICTION_PAIRS appearing in the same text
Source attribution13%Unfalsifiable sources and unnamed authorities, offset by verifiable citations
Commitment escalation14%Foot-in-the-door progression — splits text into thirds and measures whether commitment intensity increases

Markers

All marker definitions live in markers.py as static word/phrase lists. They are plain data — no models, no magic.

Tradition categories covered:

  • Generic New Age
  • Prosperity gospel
  • Conspirituality
  • New Age commercial exploitation
  • High-demand group (cult) rhetoric
  • Fraternal/secret society traditions

You can inspect the markers programmatically:

from si_protocols.markers import VAGUE_ADJECTIVES, CONTRADICTION_PAIRS

# List all vague adjectives
print(sorted(VAGUE_ADJECTIVES))

# List contradiction pair labels
for label, pole_a, pole_b in CONTRADICTION_PAIRS:
    print(f"{label}: {pole_a[0]} vs. {pole_b[0]}")

All markers are lowercase. Matching is case-insensitive (the analyser lowercases input text before comparison).