# `Arcana.Graph.CommunitySummarizer`
[🔗](https://github.com/georgeguimaraes/arcana/blob/main/lib/arcana/graph/community_summarizer.ex#L1)

Behaviour for community summarization in GraphRAG.

Community summarizers generate natural language descriptions of
entity communities. These summaries provide high-level context
for global queries that need broad understanding rather than
specific document chunks.

## Built-in Implementations

- `Arcana.Graph.CommunitySummarizer.LLM` - LLM-based summarization (default)

## Configuration

Configure your community summarizer in `config.exs`:

    # Default: LLM-based summarization
    config :arcana, :graph,
      community_summarizer: {Arcana.Graph.CommunitySummarizer.LLM, llm: &MyApp.llm/3}

    # Disable summarization (communities won't have summaries)
    config :arcana, :graph,
      community_summarizer: nil

    # Custom module implementing this behaviour
    config :arcana, :graph,
      community_summarizer: {MyApp.ExtractiveSum, max_sentences: 3}

    # Inline function
    config :arcana, :graph,
      community_summarizer: fn entities, relationships, _opts ->
        {:ok, "Community with #{length(entities)} entities"}
      end

## Implementing a Custom Summarizer

Create a module that implements this behaviour:

    defmodule MyApp.ExtractiveSum do
      @behaviour Arcana.Graph.CommunitySummarizer

      @impl true
      def summarize(entities, relationships, opts) do
        max_sentences = Keyword.get(opts, :max_sentences, 3)
        # Extract key sentences from entity descriptions...
        {:ok, summary}
      end
    end

## Summary Format

Summarizers should return a concise string (2-5 sentences) that:
- Identifies the community's central theme or domain
- Names the most important entities
- Describes key relationships between entities

# `summarize`

```elixir
@callback summarize(entities :: [map()], relationships :: [map()], opts :: keyword()) ::
  {:ok, String.t()} | {:error, term()}
```

Generates a summary for a community.

## Parameters

- `entities` - List of entity maps with `:name`, `:type`, and optional `:description`
- `relationships` - List of relationship maps connecting entities
- `opts` - Options passed from the summarizer configuration

## Returns

- `{:ok, summary}` - The generated summary string
- `{:error, reason}` - On failure

# `content_fingerprint`

Digest of the entities and relationships a summary was generated from.

Membership alone can't answer "is this summary still accurate?": a summary
is written from relationship text too, and ingesting another document adds
relationships without moving anyone between communities. Storing this
alongside the summary is what makes the question answerable later.

Covers the fields a summarizer is given: entity name, type and
description, and relationship type and description. The built-in prompt
only renders names and types, so a description edit can cost one redundant
call - deliberate, since a custom summarizer is free to read descriptions,
and over-refreshing is the safe direction. It never goes the other way.

# `default_threshold`

The change-count threshold above which a clean summary is regenerated.

Exposed so callers that predict what a summarize run will process (the
dashboard's hint, for one) can apply the same rule.

# `needs_regeneration?`

Checks if a community needs its summary regenerated.

## Regeneration Triggers

  - `dirty: true` - Community was modified since last summary
  - `change_count >= threshold` - Many changes accumulated
  - `summary: nil` - No summary exists yet
  - `summary_fingerprint: nil` - Summary predates fingerprinting, so there
    is no way to tell whether it still matches the graph. It regenerates
    once, the run records a fingerprint, and it settles from then on

## Options

  - `:threshold` - Number of changes before regeneration (default: 10)

# `reset_change_tracking`

Returns a map of fields to reset after regenerating a summary.

Use with `Ecto.Changeset.change/2` to mark a community as clean:

    community
    |> Community.changeset(CommunitySummarizer.reset_change_tracking())
    |> Repo.update()

# `summarize`

Generates a summary using the configured summarizer.

The summarizer can be:
- A `{module, opts}` tuple where module implements this behaviour
- A function `(entities, relationships, opts) -> {:ok, summary} | {:error, reason}`
- `nil` to skip summarization (returns empty string)

Falls back to LLM summarizer if not configured but `:llm` option is provided.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
