Skip to content

Motifs & Aggregation

Beam search hands back a list of surviving paths, but a list of paths is rarely what you actually want; patterns are. Aggregation is the final stage of retrieval: it folds the paths into recurring motifs, a breakdown of relation shares, and a summary of quality signals that the triage score is computed from.

Motifs turn paths into patterns

A motif is a recurring relation sequence across the returned paths, for instance billed_by -> flagged_in showing up again and again. That repetition is usually the real finding, so Odin counts it for you:

for m in result["aggregates"]["motifs"]:
    print(m)
    # e.g. {"pattern": "billed_by->flagged_in", "edge_count": 24, "path_count": 12}

This doubles as lightweight anomaly detection. One suspicious chain is a coincidence; the same chain appearing 47 times is signal. Alongside the motifs, relation_share reports how the edges break down by relation type, a quick fingerprint of what kind of connections dominate a retrieval, and the strongest one is surfaced separately as dominant_relation.

The summary is the raw material for scoring

Aggregation also computes a summary of quality signals over the paths. These are not just diagnostics; they are the exact inputs the triage score consumes:

Field Meaning
total_paths Number of paths returned
unique_motifs Distinct motif shapes
unique_relations Distinct relation types
total_edges Edges across all paths
provenance Fraction of edges with a source/provenance reference
recency Recency-weighted freshness of the edges
label_coverage Fraction of nodes/edges that are properly labeled
motif_density How concentrated the results are into repeated motifs
has_baseline Whether a baseline comparison was available
low_support True when there is too little evidence to be confident

Read together they tell a story about trustworthiness: provenance and recency reward well-sourced, fresh evidence, label_coverage guards against unlabeled noise, and low_support flags results too thin to stand behind.

Surprise comes from a baseline

When a baseline set of paths is available, aggregation compares the current retrieval against it to compute surprise: how far the dominant pattern deviates from what the prior distribution led you to expect. Surprise carries real weight in the triage score, because an unexpected result is often the one most worth an agent's attention.

The whole thing arrives under a single key:

result["aggregates"] = {
    "motifs":          [ {"pattern": "billed_by->flagged_in", "edge_count": N,
                          "path_count": M, "avg_edge_conf": 0.88,
                          "median_recency_days": 5.0}, ... ],
    "relation_share":  { "billed_by": {"count": N, "share": 0.42}, ... },
    "snippet_anchors": [ ... ],
    "summary":         { "total_paths": ..., "provenance": ..., ... },
}

These summary signals do not stay separate for long. Triage & Insight Scoring is where they collapse into one number, and the Result Schema documents every field in full.