# How this documentation is generated

Every page on this site is a Markdown file in git. Most pages were written by
people. Some were **drafted by the pipeline** after a merge to `master` changed
something a customer can observe, then reviewed and approved by a human before
they appeared here.

This page follows one real-shaped merge through that pipeline, end to end, and
shows exactly what the machine produces at each step and what it leaves alone.

{% callout type="note" title="The rule that governs everything below" %}
Every tier outputs a **pull request**, never a publish. The machine proposes; a
human disposes. Nothing on this site changes without a person clicking approve.
{% /callout %}

## The merge we will follow

A release of the Admin service lands on `master` in `id-verification-service`.
The squash commit touches 41 files. Three of the changes matter for this story:

| Change in the merge | Kind | Customer-visible? |
|---|---|---|
| New optional field `livenessCheck` on `POST /v1/workflows/{id}/steps` | Public API surface | **Yes** |
| Upgrade of the Microblink BlinkID SDK from 6.x to 7.x | Vendor dependency | Yes, but the vendor must not be named |
| Repository layer refactor: `WorkflowRepo` split into three classes | Internal refactor | **No** |

The pipeline's job is to produce documentation for the first two and stay
silent about the third.

## Step by step

{% step n=1 title="Trigger: merge to master" %}
A GitHub Action fires on every push to `master`. It checks out the merge
commit and its parent, and collects three inputs:

- The pull request title, body and file list
- The committed `openapi-external.json` at both commits
- The repository's disclosure policy file

```yaml
# .github/workflows/continuous-docs.yml
on:
  push:
    branches: [master]
jobs:
  docs:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with: { fetch-depth: 2 }
      - run: npx continuous-docs run --base HEAD~1 --head HEAD
```

Nothing has been judged yet. This step only gathers evidence.
{% /step %}

{% step n=2 title="Relevance filter: did anything observable change?" %}
This is the component that makes the pipeline trustworthy. It answers one
question per surface.

**For the API surface the answer is deterministic.** The external spec is
generated from code and CI fails if it drifts, so a structural diff of the two
committed versions *is* the customer-visible API changelog.

```diff
 "paths": {
   "/v1/workflows/{id}/steps": {
     "post": {
       "requestBody": { "schema": { "properties": {
         "type":          { "type": "string", "enum": ["document", "selfie", "aml"] },
+        "livenessCheck": { "type": "boolean", "default": false,
+                           "description": "Require an active liveness check on the selfie step." },
```

One added property. Nothing removed, nothing renamed. Classified as
**additive, non-breaking**.

**For everything else the answer is a judgment call**, so an LLM reads the PR
and the file list with the disclosure policy in its context, and returns a
structured verdict rather than prose:

```json
{
  "observable": true,
  "reasons": [
    "New public request field `livenessCheck` on workflow steps",
    "Document recognition coverage expanded (vendor SDK upgrade)"
  ],
  "ignored": [
    "src/repositories/** refactor: no behavioural change, no public surface"
  ],
  "affectedPages": ["knowledge-base/workflows/configuring-steps.md"],
  "confidence": 0.86
}
```

{% callout type="tip" title="What got ignored is part of the output" %}
The `ignored` list is shown on the resulting pull request. A reviewer can see
that the refactor was considered and correctly dropped. A filter that only
reports successes cannot be trusted; a correct silence proves it is real.
{% /callout %}
{% /step %}

{% step n=3 title="Tier 1: API reference, generated from a template" %}
The API reference page for this endpoint is regenerated directly from the
external spec. No language model is involved, so this tier is safe to
auto-merge.

{% callout type="generated" title="Generated: API reference fragment" %}
**Request body** — `POST /v1/workflows/{id}/steps`

| Field | Type | Required | Description |
|---|---|---|---|
| `type` | `string` | yes | One of `document`, `selfie`, `aml`. |
| `livenessCheck` | `boolean` | no | Require an active liveness check on the selfie step. Default `false`. |
{% /callout %}

The page carries front matter that records its provenance, so the site can show
a "generated from spec" badge and a reviewer can trace it back to a commit:

```yaml
---
title: Create a workflow step
generated_by: continuous-docs
tier: 1
source: id-verification-service/openapi-external.json
source_commit: 9f3c1a7
---
```
{% /step %}

{% step n=4 title="Tier 2: changelog entry, LLM prose over a structured diff" %}
The same spec diff, plus the filter's structured verdict, is handed to a model
with one instruction: write a customer-facing changelog entry. The disclosure
policy is applied **before** the text is written, not scrubbed afterwards.

```yaml
# .continuous-docs/policy.yml (id-verification-service)
disclosure:
  never_name:
    - Microblink
    - BlinkID
    - Regula
    - Hopae
    - IDRnD
    - EyeDP
  internal_only_concepts:
    - "fraud score thresholds"
    - "internal queue names"
```

{% callout type="generated" title="Generated: changelog entry" %}
**2026-09-02 — ID Verification**

- Workflow selfie steps can now require an **active liveness check**. Set
  `livenessCheck: true` when creating a step via `POST /v1/workflows/{id}/steps`.
- **Expanded document recognition coverage** for identity documents across
  additional countries and document formats.
{% /callout %}

Notice the second bullet. The merge upgraded a named vendor SDK; the entry says
what the customer gains and names nobody. The same redaction already holds on
the API surface, where the external spec contains zero mentions of any vendor.
This tier gets a light review because the facts came from the diff and only the
wording came from the model.
{% /step %}

{% step n=5 title="Tier 3: knowledge-base draft, mandatory human review" %}
The filter identified one conceptual page that now describes the product
incompletely. The model is given the current page, the diff, the verdict and
the policy, and asked to propose the smallest edit that makes the page true
again.

{% callout type="generated" title="Generated: proposed edit to knowledge-base/workflows/configuring-steps.md" %}
```diff
 ## Selfie step

 The selfie step captures a live photo and compares it against the document
 portrait. It runs after the document step by default.
+
+### Requiring an active liveness check
+
+Set `livenessCheck: true` on the step to require the user to complete an
+active liveness challenge (for example, turning their head) before the
+selfie is accepted. This raises assurance against presentation attacks at
+the cost of a slightly longer session. It is off by default.
```
{% /callout %}

{% callout type="human" title="Human: this is where review actually matters" %}
A confidently worded wrong sentence on a public page is worse than a stale one.
Some of these pages are effectively contractual for regulated customers, so
Tier 3 output is **never** merged without a named reviewer. The confidence
score from the filter tells them where to look hardest.
{% /callout %}
{% /step %}

{% step n=6 title="Output: one pull request against this docs repository" %}
All three tiers land in a single pull request against the docs site. Its body
is generated too, and it is written for the reviewer rather than the customer.

```markdown
## Docs update for id-verification-service#1284 — "Admin release 2026.09"

**Detected (customer-visible)**
- Additive API change: `livenessCheck` on POST /v1/workflows/{id}/steps
- Expanded document recognition coverage (vendor name redacted per policy)

**Ignored (not customer-visible)**
- Repository layer refactor under src/repositories/** — no public surface

**Changes in this PR**
| File | Tier | Gate | Confidence |
|---|---|---|---|
| api-reference/workflows/create-step.md | 1 | auto | — |
| changelog/2026-09.md | 2 | light review | 0.91 |
| knowledge-base/workflows/configuring-steps.md | 3 | **required** | 0.86 |

Source commit: id-verification-service@9f3c1a7
```

The reviewer approves. The site rebuilds. The page you are reading renders the
updated Markdown, and the raw `.md` file is served at a predictable URL so the
next coding agent that integrates SEON reads the truth as of the last merge.
{% /step %}

## The merge that produces nothing

The day before, a different merge landed: the same repository refactor, on its
own, with no spec change. The pipeline ran and produced this:

```json
{
  "observable": false,
  "reasons": [],
  "ignored": ["src/repositories/** refactor: no behavioural change, no public surface"],
  "affectedPages": [],
  "confidence": 0.97
}
```

No pull request was opened. No one was notified. That silence is the feature:
a pipeline that opens a PR on every merge gets muted inside a week, and muted
pipelines do not come back.

## What each tier trusts

| Tier | Surface | Detection | Drafting | Gate |
|---|---|---|---|---|
| 1 | API reference | Structural diff of `openapi-external.json` | Template | Auto-merge |
| 2 | Changelog | Same diff plus externally tagged releases | LLM prose over a structured diff | Light review |
| 3 | Knowledge base | LLM judgment over the pull request | LLM | Mandatory human review |

{% callout type="warning" title="Provenance is visible on every page" %}
Pages drafted by the pipeline carry `generated_by`, `tier` and `source_commit`
in their front matter. Readers and reviewers can always tell how a page came to
be and which commit it describes.
{% /callout %}
