intelligence 7 min read

OSINT Signal Synthesis: Applying the GRACE Framework in Production

How Prismatic applies the GRACE framework to fuse heterogeneous OSINT signals into calibrated intelligence. A practical walk-through from raw adapter output to decision-grade evidence.

Tomáš Korcak (korczis) 400 words

Raw OSINT output is noise until it is fused. A Czech ARES hit, a Shodan banner, and a certificate-transparency log line each carry a fragment of truth — and a unique failure mode. The GRACE framework (Gather, Rank, Attribute, Correlate, Evidence) is how Prismatic turns that fragmentation into decision-grade intelligence.

Why fusion, not aggregation

Aggregation stacks results. Fusion reconciles them. When two OSINT adapters disagree about an entity's registered address, the pipeline must decide which signal to trust, by how much, and for how long. That decision has to be auditable — otherwise every downstream call is guessing.

GRACE gives each stage a contract:

  • Gather — pull from registered adapters, record provenance.
  • Rank — assign a confidence tier per source × query-type.
  • Attribute — tag every field with source + timestamp.
  • Correlate — merge identities via entity resolution.
  • Evidence — emit a sealed envelope the decision engine can consume.

The pipeline in Elixir

def synthesize(query, opts \\ []) do
  query
  |> PrismaticOsintCore.gather(opts)        # Gather
  |> Enum.map(&rank_source/1)                # Rank
  |> Enum.flat_map(&attribute_fields/1)      # Attribute
  |> EntityResolver.correlate()              # Correlate
  |> DecisionEnvelope.seal()                 # Evidence
end

Each stage emits telemetry — [:osint, :grace, :stage, :stop] — so latency regressions show up in the dashboard before users see them.

Confidence tiers are not optional

A flat "score" is a trap. It hides source diversity. Prismatic assigns tiers per adapter per query-type:

TierMeaningExample
T1Official registryCzech ARES, UK Companies House
T2Enriched commercialShodan, BuiltWith
T3Derived / inferredSocial graph inference
T4Unverified / scrapedForum mentions

A T1 ARES record beats ten T4 forum posts. Always. The ranker encodes that invariant so no LiveView has to re-implement it.

Sealed evidence envelopes

The output of GRACE is not a map — it is a sealed envelope:

%DecisionEnvelope{
  query: "Navigara s.r.o.",
  fields: [%{key: :address, value: "...", source: "czech-ares", tier: :t1, ts: ~U[...]}, ...],
  confidence: 0.87,
  provenance: [...],
  sealed_at: ~U[2026-04-09 10:00:00Z]
}

Sealed means immutable. Once an envelope is produced, it is the audit record. The decision engine can reject it, but it cannot silently rewrite it — which is exactly the property No Mercy, No Doubts requires.

Where to go next

GRACE is a framework, not a library. The Academy walks through it end-to-end with a runnable case study:

Fusion is the hard part. Adapters are the easy part. Get the fusion contract right and every new adapter you add compounds in value instead of adding noise.