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

# Attestations: proof of monitoring

> The filable monthly proof-of-monitoring artifact. Fetch it, file the PDF, verify the JSON by hash, and read coverage gaps honestly.

An attestation is a filable, monthly record that a watch was actually
evaluated during a period, with the office-data horizon it covered and the
outcome (including the negative outcome). It is the artifact a law firm keeps
on file to show that a monitoring instruction was in force and was executed.

```bash theme={null}
curl "https://api.signa.so/v1/watches/wat_.../attestation?period=2026-06" \
  -H "Authorization: Bearer $SIGNA_API_KEY"
```

Requires an API key with the `portfolios:manage` scope. The period is a UTC
calendar month. Omit `period` to get the previous (most recently closed)
month.

## What it proves, and what it does not

An attestation certifies that **evaluation occurred** against the stated data
horizons: which query was in force, how many times it ran, the sync runs it
consumed, and the office-data coverage timestamps it reached.

It does **not** certify that every relevant mark was surfaced. Recall is
bounded by connector coverage and the match strategy you configured. This is a
deliberate bright line: the attestation is evidence of diligence and process,
not a guarantee of exhaustive detection. The `statement` field states this in
plain language, and the wording is subject to founder and counsel review.

## The "no alert" versus "not looking" model

The whole point of an attestation is to make silence provable. If you received
no alert for a period, the attestation shows whether that silence means "we
looked and found nothing" or "we were not looking".

* **We looked and found nothing.** `evaluations_count` is greater than zero,
  `changes_evaluated` shows the volume assessed, `match_count` is 0, and there
  are no gaps. That is a real negative result you can rely on.
* **We were not looking.** The period carries a `gaps[]` entry (see below), the
  office is marked `no_evaluations` (a supported office with zero evaluations
  in the period, disclosed with a full-period gap and no coverage claims), or
  the office is marked `unsupported`. Silence never implies coverage that did
  not happen.

If the watch is paused or disabled at the moment you fetch the artifact, the
response carries `watch_status_at_generation` so the current state is on the
record. Pause history within the period itself is not reconstructable in this
version (there is no status audit trail yet); that is a documented limitation.

## Per-office fields

Each entry in `offices[]` reports one office in the watch scope.

| Field                                | Meaning                                                                                                                                                                                                                       |
| ------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `status`                             | `evaluated` (a supported, ingested office with real claims), `no_evaluations` (a supported office with zero evaluations in the period: zero counts, no coverage claims, and a full-period gap), or `unsupported` (see below). |
| `evaluations_count`                  | Number of successful evaluations during the period. A failed evaluation is not counted as an evaluation.                                                                                                                      |
| `changes_evaluated`                  | Changes evaluated against your query this period (candidacy volume). This is the number of candidate changes assessed, not the size of the whole office corpus.                                                               |
| `match_count`                        | Candidate changes that matched your query.                                                                                                                                                                                    |
| `alerts_emitted`                     | Alerts produced from those matches.                                                                                                                                                                                           |
| `coverage_from` / `coverage_through` | The office-data timestamps the watch was current through at the start and end of the period. This is office-data time, not wall-clock time.                                                                                   |
| `coverage_basis`                     | Which signal the coverage timestamp came from: `source_dates` (strongest), `date_range`, or `run_completed` (weakest).                                                                                                        |
| `gaps`                               | Disclosed intervals where coverage fell behind (see below).                                                                                                                                                                   |

### `changes_evaluated` is candidacy volume

`changes_evaluated` is the count of candidate changes assessed against your
query, summed across the evaluations in the period. It is not a claim about how
many records exist at the office. It tells you the volume of change the watch
weighed before deciding there was nothing to alert on.

## Coverage gaps

`gaps[]` is where honest degradation is disclosed. A gap is an interval in the
period where the office-data coverage the watch had evaluated through fell
behind the internal freshness target for that office. Gap disclosure is
permanent: it stays in the artifact for that period even after coverage
recovers, because it is a fact about what happened.

```json theme={null}
"gaps": [
  {
    "from": "2026-06-11T06:00:00.000Z",
    "through": "2026-06-20T06:00:00.000Z",
    "reason": "office_lagging",
    "resolved": true
  }
]
```

* `reason: "office_lagging"` means coverage was stale beyond the office target
  for that interval.
* `resolved: true` means coverage caught back up within the period.
  `resolved: false` means it was still behind at the period boundary.

In this version, gaps cover coverage-staleness only. Evaluations that failed
outright do not write a receipt, so they are not reconstructed as gaps here.
The `evaluation_failed` reason is reserved for a future version.

Two special gap shapes to know:

* A supported office with **zero evaluations** in the period is marked
  `no_evaluations` and carries a single gap spanning the whole period. It is
  `resolved: true` only if evaluation demonstrably resumed after the period.
* Evaluations recorded **before coverage snapshots existed** cannot state what
  office-data horizon they covered. They are disclosed as incomplete coverage
  evidence (a gap with a null `coverage_through`), never presented as covered.

## Unsupported offices

If a watch is scoped to an office Signa does not currently ingest, that office
appears with `status: "unsupported"` and no evaluation claims at all. Signa
will never render a clean, zero-alert attestation for an office it does not
cover, because that would read as "we looked and found nothing" when the truth
is "we do not cover this office yet".

If **every** office in the scope is unsupported, the endpoint returns
`422 attestation_unsupported_scope` rather than an empty artifact.

## Configuration changes and the fingerprint

The `query_fingerprint` is a stable hash of the watch query and trigger
events. Its `fingerprint_basis` is `current_configuration`: it describes the
configuration as it exists when you fetch the artifact, because a full
evaluated-time configuration history is not stored yet. Two flags keep this
honest:

* `configuration_changed_in_period: true` means the configuration changed
  **during** the period (the receipts carry more than one evaluation epoch);
  the `epochs_in_period` array lists them.
* `configuration_changed_since_period: true` means the configuration changed
  **after** the period closed. The fingerprint in the artifact then describes
  the current configuration, not the one that was in force during the period.

Practical rule for firms: fetch and file the attestation promptly after the
month closes, before making configuration changes. A filed artifact with both
flags `false` pins the fingerprint to the period unambiguously.

## Reconciliation

The artifact cross-checks the alert counts recorded on the evaluation receipts
against the alert rows stored for the period, scoped to the same supported
offices the artifact reports on. When they agree, `reconciliation` is
`consistent`. When they disagree, it is `mismatch`, surfaced honestly rather
than silently reconciled to one number.

One caveat: alerts that cannot be attributed to an office (their ingestion-run
reference is null, for example because the run record aged out) are included
in the cross-check total. In rare cases this can produce a `mismatch` that
reflects attribution loss rather than a missing or extra alert.

## Verifying integrity with `content_hash`

The `content_hash` is a SHA-256 over the canonical, sorted-key form of the
artifact, excluding the fields that describe the moment of generation rather
than the period: `generated_at`, `request_id`, the hash itself,
`watch_status_at_generation`, `watch.name` (display-only), and
`watch.configuration_changed_since_period`. Because the artifact is computed
deterministically from stored receipts, re-fetching a closed period later
yields the exact same `content_hash`.

To verify a filed copy: re-fetch the JSON for the same period and compare the
`content_hash` to the value on the copy you filed. A match proves the artifact
was not altered after issue.

Note that the fingerprint of the current configuration **is** part of the
hash. If you change the watch configuration after filing, a later re-fetch
will show `configuration_changed_since_period: true` and a different hash;
that is the disclosure working as intended, not tampering.

This proves the **integrity** of the artifact. It is not a third-party
authenticity signature. Cryptographically signed and timestamped documents
(for example RFC 3161 timestamps) are on the roadmap.

## Filing the PDF

For a business record you can file, request the PDF:

```bash theme={null}
curl "https://api.signa.so/v1/watches/wat_.../attestation?period=2026-06&format=pdf" \
  -H "Authorization: Bearer $SIGNA_API_KEY" \
  -o proof-of-monitoring-2026-06.pdf
```

You can also request it with `Accept: application/pdf`. The PDF is rendered
from the same data as the JSON, so the numbers match. It includes the
configuration, a per-office coverage table, the gaps, the totals, the
statement, and the `content_hash` with instructions for verifying it against
the JSON endpoint.

A typical firm workflow: fetch the PDF once a month for the closed period, file
it in the matter record, and store the JSON alongside it so an auditor can
re-fetch and hash-verify later.

## Periods and errors

* Periods are closed UTC calendar months. The default is the previous month.
* The current, in-progress month returns `422 attestation_period_open`. Pass
  `partial=true` to get an interim artifact marked `"partial": true`.
* A period beyond the 25-month retention window returns
  `410 attestation_expired`. The window is rolling (day-granular, matching the
  evidence retention clock): once any part of a month is past the horizon, the
  whole month is treated as expired. File monthly, within the window.
* An unknown watch, or a watch belonging to another organization, returns
  `404`.
