# Authoring guide — writing high-quality OKF concept documents

The format is easy; the *quality* is the value. This guide covers how to write
concept documents that an LLM can reason over reliably.

## The golden rules
1. **One concept per file.** If a file describes two things, split it.
2. **Structure beats prose.** Tables, lists, fenced code > paragraphs. LLMs and
   humans both retrieve structured content more reliably.
3. **Ground everything.** Every non-obvious claim traces to an ingested capture
   or a citation. Never invent schemas, metrics, numbers, or APIs.
4. **Link generously.** Express relationships as markdown links so the bundle is
   a graph. A concept with no links is usually under-connected.
5. **Describe in one sentence.** `description` is a single, specific sentence —
   it is what shows up in `index.md` and search snippets.

## Frontmatter craft

```yaml
---
type: Metric
title: Weekly Active Users
description: Distinct users with at least one session in a rolling 7-day window.
resource: https://looker.acme.com/looks/wau
tags: [growth, engagement, core-metric]
timestamp: 2026-05-28T14:30:00Z
---
```

- **`type`** — pick from a small, consistent vocabulary across the bundle. Good
  sets: `Dataset` / `Table` / `Metric` / `Pipeline` / `Runbook` / `API Endpoint`
  / `Service` / `Concept` / `Decision` / `Reference`. Consistency makes the
  visualizer's type colors and filters meaningful.
- **`title`** — human-readable; don't just echo the filename.
- **`description`** — one sentence, specific. Bad: "Info about users." Good:
  "One row per registered user, keyed by `user_id`, including signup channel."
- **`resource`** — the canonical URI of the real asset (dashboard, table
  console, repo, doc). Omit for purely abstract concepts.
- **`tags`** — cross-cutting categories for filtering. Reuse tags consistently.
- **`timestamp`** — ISO 8601; update it whenever you meaningfully edit the file.

## Body patterns by concept type

### Table / dataset (use `# Schema`)
```markdown
# Schema
| Column | Type | Description |
|--------|------|-------------|
| `order_id` | STRING | Globally unique order id. |
| `customer_id` | STRING | FK to [customers](/tables/customers.md). |
| `total_usd` | NUMERIC | Order total in USD. |

# Joins
Joined with [customers](/tables/customers.md) on `customer_id`.

Part of the [sales dataset](/datasets/sales.md).
```

### Metric (definition + formula + lineage)
```markdown
Weekly Active Users (WAU) counts distinct `user_id`s with ≥1 session in a
rolling 7-day window.

# Definition
- Source: [sessions](/tables/sessions.md)
- Window: rolling 7 days, computed daily
- Excludes: internal users (`is_staff = true`)

# Examples
```sql
SELECT COUNT(DISTINCT user_id)
FROM sessions
WHERE session_ts >= TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 7 DAY)
  AND NOT is_staff;
```
```

### Runbook / playbook (trigger → steps)
```markdown
# Trigger
Freshness alert when [orders](/tables/orders.md) lags >30 min behind SLA.

# Steps
1. Check the [ingestion pipeline](/pipelines/orders-ingest.md) dashboard.
2. If the job failed, restart it and confirm backfill.
3. Escalate to on-call if lag exceeds 2h.
```

### Reference (mirrored external doc)
Put external material you want first-class under `references/`, with a
`# Citations` link back to the original source.

## Cross-linking well
- Prefer **bundle-absolute** links: `[customers](/tables/customers.md)`.
- Link the **first meaningful mention** of a related concept in the body.
- Make relationships explicit in prose: "depends on", "joined with",
  "supersedes", "owned by" — the link is untyped, the prose carries the meaning.
- Avoid orphans: if `link_check.py` reports an orphan, find where it belongs in
  the graph and link it both ways where natural.

## Citations
```markdown
# Citations
[1] [GA4 BigQuery export schema](https://developers.google.com/analytics/bigquery)
[2] [Internal data-quality runbook](/references/data-quality.md)
```
Cite whenever a claim came from outside the obvious source. Citations are how a
consumer (human or agent) verifies the knowledge.

## Anti-patterns to avoid
- ❌ Source-shaped folders (`notion/`, `pdf/`) — organize by consumer topic.
- ❌ Mega-files describing many concepts — split them.
- ❌ Empty or vague `description`, missing `type`.
- ❌ Inventing schema columns, metric formulas, or endpoints not in the sources.
- ❌ Walls of prose with no headings/tables.
- ❌ Dumping raw capture text verbatim — synthesize and structure it.
- ❌ Leaving secrets/tokens from sources in the bundle — redact them.

## Self-review checklist (before declaring done)
- [ ] `validate_okf.py` → 0 errors.
- [ ] Every concept has a non-empty `type` and a one-sentence `description`.
- [ ] `link_check.py` → no surprising broken links; orphans justified.
- [ ] Every directory has a current `index.md` (`build_index.py --write`).
- [ ] Claims trace to captures or citations; nothing invented.
- [ ] `viz.html` graph looks connected and sensibly typed.
