> ## Documentation Index
> Fetch the complete documentation index at: https://filetrace.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# File attribution and confidence levels

> How Filetrace ties bytes sent on a socket to a file, through sendfile or a read followed by a send, and what the EXACT, INFERRED and UNKNOWN levels guarantee.

Filetrace does not inspect packet payloads. It attributes bytes sent on a socket to a file by watching what the kernel does on behalf of the sending thread, and it labels every attribution with a confidence level that states what the association rests on. This page explains the two attribution methods, the thresholds that decide when an association is reported, and how to read the confidence of a record.

## Confidence levels

| Level | Method | Meaning |
| - | - | - |
| **EXACT** | `sendfile` | The kernel moved the file's data to the socket in one operation. |
| **INFERRED** | `read-write` | A thread read the file and then sent on the socket. The payload cannot be proven to come only from that file. |
| **UNKNOWN** | | Bytes were sent and no file could be associated with them. |
| **STRONG** | | Defined for provenance followed through intermediate operations. No probe produces it. |

A level is never raised by a filter or an output format, and every record lists the evidence behind it. In tables, a `*` after the level marks a transfer during which events were lost, so its byte counts may be incomplete.

## Exact attribution with sendfile

When a program calls `sendfile(2)`, the kernel copies data from a file to a socket inside one operation (`do_splice_direct`). The probe sees the file and the socket in the same call, so the association is certain. Web servers such as nginx serve static files this way.

```text theme={null}
FILE                 PROCESS  DESTINATION    BYTES    METHOD    CONFIDENCE
/var/www/video.mp4   nginx    198.51.100.10  47.7 MB  sendfile  EXACT
```

## Inferred attribution with read and send

Most programs read a file into a buffer and then write the buffer to a socket. The kernel never sees the two operations as one, so Filetrace correlates them per thread:

1. The `vfs_read` probe records which regular file each thread read last, and how much.
2. When the same thread sends on a socket within the **correlation window** (2 seconds by default) after that read, with no receive in between, the send is associated with the file.
3. The association covers at most as many bytes as the thread read.
4. It is reported once it covers at least **1 KB** and **5%** of what was read from the file.

```text theme={null}
FILE                        PROCESS  DESTINATION   BYTES    METHOD      CONFIDENCE
/data/export/customers.csv  python   203.0.113.50  11.4 MB  read-write  INFERRED
```

The receive rule keeps request and response traffic apart: a thread that reads a file, then hears from its peer, then sends something else has not sent the file. For example, a certificate bundle read before a TLS handshake is not attributed to the connection, because the handshake's receive ends the association.

The settings live in the `[correlation]` section of the configuration file:

```toml theme={null}
[correlation]
enabled = true
window = "2s"                       # longest read-to-send gap that still associates
confidence_threshold = "inferred"   # "exact" reports sendfile only
inferred_min_bytes = "1KB"
inferred_min_percent = 5
```

## When an inferred association is wrong

An INFERRED record is a strong hint, not proof. It can be wrong when a thread reads one file and then sends unrelated data of a similar size without receiving in between. It can also be missing:

* A file read by one thread and sent by another, or passed through a pipe, is not associated with the send.
* Files read with `readv`, io\_uring or through a memory mapping are not seen as read. Bytes sent through io\_uring are still counted per socket.

[Known limitations](https://filetrace.mintlify.site/reference/limitations.md) lists every case.

## Unattributed bytes

Bytes that no file accounts for are not dropped. They appear as UNKNOWN in `filetrace transfers`, which shows `unknown` in the `FILE` column, and in `filetrace files --include-unknown`. The share of outbound traffic that files account for is a useful signal on its own:

```promql theme={null}
sum(rate(filetrace_file_sent_bytes_total[5m]))
  / sum(rate(filetrace_network_io_bytes_total{network_io_direction="transmit"}[5m]))
```

## Evidence

Machine-readable output lists the evidence behind each record in `transfer.evidence`. A sendfile transfer carries, for example:

```json theme={null}
"evidence": ["direct_file_to_socket_transfer", "file_identity",
             "socket_identity", "remote_endpoint"]
```

## What a byte count means

Byte counts are what the local socket accepted. They are not the number of bytes on the wire and not what the remote end acknowledged. For a read-write transfer, three numbers describe the file: `file.size` (its size when it was first seen), `transfer.bytes_read` (what the thread read from it) and `transfer.bytes_sent` (what the socket accepted). See [Records and identifiers](https://filetrace.mintlify.site/concepts/data-model.md).

## Filter by confidence

`filetrace files`, `transfers` and `watch` accept `--confidence`:

```bash theme={null}
filetrace files --confidence exact --min-bytes 100MB
filetrace transfers --confidence unknown --since 30m
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.