# `absentia.toml` Reference

Absentia reads `absentia.toml` from the project root (or any ancestor
of the path you pass to `absentia check`). Every section is optional;
defaults below are sensible starting points. `absentia init` writes
a working `absentia.toml` for you.

A working sample with comments lives at `absentia.toml.example` in
the repo root.

## `[scan]` — what to look at

| Key | Type | Default | Meaning |
|---|---|---|---|
| `include` | list of glob | `["."]` | Directories or globs to scan. POSIX-style, relative to the project root. |
| `exclude` | list of glob | `[]` | Paths to skip. Use for vendored code, generated files, etc. |
| `languages` | list of string | all 17 supported | Which extractors to load. Omitting the key activates every built-in extractor. Set explicitly to scan a subset (e.g. `["python", "rust"]`). |

Supported `languages` values (17 built-in extractors covering 16
languages — TypeScript and TSX share a tree-sitter grammar but emit
distinct extractors): `python`, `javascript`, `typescript`,
`tsx`, `rust`, `go`, `java`, `ruby`, `csharp`, `swift`, `c`, `cpp`,
`php`, `kotlin`, `scala`, `lua`, `bash`.

```toml
[scan]
include   = ["src/", "tests/"]
exclude   = ["src/vendor/", "**/generated/"]
languages = ["python"]
```

## `[mining]` — when to flag a divergence

| Key | Type | Default | Meaning |
|---|---|---|---|
| `min_confidence` | float | `0.8` | A feature value must appear in at least this fraction of an eligible group's members to become a rule. Higher = stricter; fewer but sturdier rules. |
| `min_group_size` | int | `3` | Groups smaller than this are skipped — too small for the statistics to mean anything. |

```toml
[mining]
min_confidence = 0.8
min_group_size = 5
```

CLI overrides: `absentia check --min-confidence 0.9 --min-group-size 10`.

## `[selectors.*]` — how groups are formed

Selectors organize entities into groups whose members get compared
against each other. See the [selectors reference](selectors.md)
for the full per-selector explanation; this section is the schema.

### `[selectors.directory]`

| Key | Type | Default | Meaning |
|---|---|---|---|
| `enabled` | bool | `true` | Toggle this selector. |
| `min_members` | int | `3` | Skip directories with fewer entities. |
| `kind_filter` | list of string | `["function", "class", "module"]` | Only group entities of these kinds. The `module` kind is one-per-Python-file; it's included by default so module-level features like `has_all_export` can be mined alongside function/class conventions. |

### `[selectors.decorator]`

| Key | Type | Default | Meaning |
|---|---|---|---|
| `enabled` | bool | `true` | Toggle this selector. |
| `min_members` | int | `3` | Skip decorators carried by fewer entities. |
| `exclude` | list of string | `["@property", "@staticmethod", "@classmethod"]` | Decorator values to ignore (typically universal builtins that wouldn't form interesting rules). |

### `[selectors.parent_class]`

| Key | Type | Default | Meaning |
|---|---|---|---|
| `enabled` | bool | `true` | Toggle this selector. |
| `min_members` | int | `3` | Skip parent classes with fewer subclasses. |
| `exclude` | list of string | `["object"]` | Parent classes too universal to group on. |
| `kind_filter` | list of string | class-like kinds across all supported languages | Kinds eligible for grouping: `class`, `struct`, `enum`, `extension`, `protocol`, `interface`, `trait`, `impl`, `module`, `record`. |

```toml
[selectors.directory]
enabled     = true
min_members = 5
kind_filter = ["function", "class"]

[selectors.decorator]
enabled     = true
min_members = 3
exclude     = ["@property", "@staticmethod"]

[selectors.parent_class]
enabled     = true
min_members = 3
```

## Project-wide `[[suppress]]` blocks

Mark gaps as known/intentional in the version-controlled config so
the suppression sticks across teammates and CI runs (vs the local
`absentia suppress <gap-id>` flow, which writes to the gitignored
`.absentia/state.db`):

```toml
[[suppress]]
entity  = "src/api/users.py::delete_user"
rule    = "@audit"
reason  = "delete_user IS the audit endpoint"
created = "2026-05-08"

[[suppress]]
rule    = "@deprecated"
scope   = "rule_global"
reason  = "ignoring @deprecated conventions for now"
```

| Field | Required? | Meaning |
|---|---|---|
| `entity` | for `scope = "gap"` | Full qualified name (`<file>::<scope>`). Exact match. |
| `rule` | for `scope = "rule_global"`, optional otherwise | Either the rule's feature value (e.g. `"@audit"` — what shows in gap output) or its full id (`<group>::<kind>=<value>`). |
| `scope` | optional | `"gap"` (default) suppresses one (entity, rule) pair. `"rule_global"` suppresses every gap from this rule, anywhere. |
| `reason` | recommended | Documentation. Surfaces in `absentia suppress --list`. |
| `created` | optional | ISO-8601 date. Useful when auditing stale suppressions. |

Malformed `[[suppress]]` blocks are silently dropped (advisory
enforcement, not load-bearing for the scan). The TUI's view 5
shows project-source suppressions as read-only — edit
`absentia.toml` directly via `,` → `e` to remove or change them.

## Previewed in `absentia.toml.example` but not yet wired

The example file previews several sections that are **not yet
implemented in the engine**: the `name_pattern` and `cluster`
selectors, `[[selectors.manual]]`, `[output]`, and
`max_predicate_size` under `[mining]`. Treat them as a roadmap;
the sections above are what `absentia check` actually reads today.

For ad-hoc / personal suppressions (the only kind currently
supported), use `absentia suppress <gap-id> --reason "..."` or press
`s` in the TUI. Those live in `.absentia/state.db` and aren't
committed to version control.
