# Độ phủ: từng phần của app có đang được theo dõi thật không

> Khai báo mỗi phần của app phải gửi gì, Belvador đối chiếu với thứ thật sự nhận được: đã xác minh, cũ, có vấn đề hay chưa biết; quản lý bằng code từ CI.

**Độ phủ** trả lời trung thực một câu hỏi: *từng phần của app có thật sự đang được theo dõi không?* Bạn khai báo app cần gửi gì — ví dụ lỗi trình duyệt và server ở production, check-in của job chạy mỗi đêm — và Belvador đối chiếu từng khai báo với những gì thật sự tới. Không có lỗi không bao giờ được tính là đã kết nối: tín hiệu chưa từng tới là **chưa biết**, không phải ổn.

Mở **Độ phủ** trong workspace để xem mọi project cùng lúc, hoặc **Project → Độ phủ** để sửa kỳ vọng của một project. Viewer xem được; thành viên trở lên sửa được.

## Trạng thái

Mỗi tín hiệu đã khai báo có một trạng thái, tính ở một nơi duy nhất phía Belvador — trang, [API](https://belvador.dev/vi/docs/reference/api) và công cụ [MCP](https://belvador.dev/vi/docs/mcp) `get_coverage` cho ra cùng con số.

| Trạng thái | Nghĩa là |
|---|---|
| **Đã xác minh** | Dữ liệu thật hoặc [biên nhận xác minh](https://belvador.dev/vi/docs/node/connection) đã tới từ đúng phần đó của app, đúng môi trường, trong cửa sổ *coi là cũ sau* (mặc định 168 giờ) |
| **Cũ** | Từng tới, nhưng không trong cửa sổ — có thể có gì đó đã ngừng gửi |
| **Có vấn đề** | Đang có sự cố kết nối liên quan, ví dụ SDK báo bị bỏ event; trạng thái này thắng dữ liệu mới cho tới khi sự cố được xử lý |
| **Chưa biết** | Chưa từng có gì tới |

Tỷ lệ ở đầu trang — *34/41 kỳ vọng đã xác minh* — chỉ đếm tín hiệu **đã xác minh**. Cũ, có vấn đề và chưa biết không bao giờ được tính là đã phủ.

## Mỗi phần gửi được gì

Một kỳ vọng là một **môi trường** × một **phần** (surface) của app × các **tín hiệu** phần đó cần gửi:

| Phần của app | Lỗi (`errors`) | Traces (`traces`) | Logs (`logs`) | Metrics (`metrics`) | Check-in (`check_ins`) | Web vitals (`web_vitals`) | Kiểm uptime (`probes`) |
|---|---|---|---|---|---|---|---|
| Trình duyệt (`browser`) | có | có | có | — | — | sau (chưa thu) | — |
| Server (`server`) | có | có | có | có | — | — | — |
| Worker (`worker`) | có | có | có | có | — | — | — |
| Job (`job`) | có | có | có | — | có | — | — |
| Edge function (`edge_function`) | có | có | có | có | — | — | — |
| Database (`database`) | — | có | — | có | — | — | — |
| Uptime (`uptime`) | — | — | — | — | — | — | có |

Metrics được tính khi node chạy agent 0.1.37 trở lên ([Metrics](https://belvador.dev/vi/docs/otel/metrics)); trên node cũ hơn, ô metrics giữ *Chưa biết*. Web vitals có trong từ vựng nhưng Belvador chưa thu thập, nên chưa khai báo được — độ phủ không hứa điều chưa đo được.

## Belvador biết phần nào đã gửi bằng cách nào

Node của bạn xác định phần (surface) của từng lỗi, span, log và check-in nó lưu, dựa trên thông tin các SDK chuẩn vốn đã gửi:

- **Lỗi** (Sentry SDK): lỗi trong một job có monitor (`contexts.monitor`) → **job**; SDK trình duyệt → **trình duyệt**; task hàng đợi (`contexts.trace.op` bắt đầu bằng `queue.`) → **worker**; hàm serverless (SDK Cloudflare, Vercel Edge, AWS Lambda, Google Cloud Functions, hoặc `cloud.platform` / `faas.trigger` theo [quy ước FaaS của OpenTelemetry](https://opentelemetry.io/docs/specs/semconv/faas/)) → **edge function** — trigger `timer` tính là **job**, `pubsub` là **worker**; còn lại → **server**.
- **Trace và log** (OpenTelemetry): SDK trình duyệt (`telemetry.sdk.language = webjs`) → **trình duyệt**; thuộc tính FaaS như trên → **edge function**; span consumer có `messaging.system` → **worker**; span có `db.system.name` được tính thêm là trace của **database**. Dữ liệu thiếu `deployment.environment.name` được tính là `production`, giống Sentry SDK.
- **Check-in** → **job**. **Uptime** lấy từ các [kiểm tra uptime](https://belvador.dev/vi/docs/uptime/quickstart) của bạn.

## Khai báo kỳ vọng

1. Mở **Project → Độ phủ**.
2. Project chưa khai báo gì sẽ có **bộ gợi ý** theo framework — với TanStack Start là lỗi trình duyệt và server ở môi trường chính. Chọn **Dùng gợi ý**, hoặc **Thêm kỳ vọng**.
3. Chọn môi trường đúng như SDK gửi, chọn phần và tín hiệu. **Coi là cũ sau** là bao lâu không có bằng chứng thì chuyển sang cũ (1–720 giờ): chọn dài hơn khoảng cách thường gặp giữa hai lần có dữ liệu thật — job chạy mỗi đêm cần khoảng 26.

**Xác minh ngay** trên một tín hiệu mở [bước kiểm tra kết nối](https://belvador.dev/vi/docs/node/connection) của project cho môi trường đó: chạy xong, biên nhận tới là tín hiệu chuyển sang đã xác minh.

## Thấy nhưng chưa khai báo

Tín hiệu Belvador thấy trong 30 ngày qua mà chưa có kỳ vọng nào được liệt kê ở **Thấy nhưng chưa khai báo**, kèm nút **Thêm vào kỳ vọng**. Chúng không làm đổi tỷ lệ cho tới khi bạn khai báo.

## Quản lý bằng code

Giữ kỳ vọng cạnh code và áp dụng từ CI. Bộ kỳ vọng ghi theo cách này là **quản lý bằng code**: app chỉ hiển thị, không cho sửa, để một cú bấm không ghi đè được file.

```yaml title="belvador-coverage.yaml"
config_source: code
expectations:
  - environment: production
    surface: browser
    signals: [errors]
  - environment: production
    surface: server
    signals: [errors, traces]
  - environment: production
    surface: job
    signals: [check_ins]
    stale_after_hours: 26
    note: nightly billing
```

```bash title="Bước CI"
yq -o=json belvador-coverage.yaml | curl --fail-with-body -X PUT \
  "https://api.belvador.dev/v1/projects/$BELVADOR_PROJECT_ID/coverage-expectations" \
  -H "Authorization: Bearer $BELVADOR_TOKEN" \
  -H "Content-Type: application/json" \
  --data-binary @-
```

Token cần quyền `coverage:write` (token dịch vụ ở **Cài đặt workspace → Service accounts** hợp với CI). Mỗi lần gọi thay cả bộ kỳ vọng của project; gửi lại đúng file đó không đổi gì. Muốn trả quyền sửa về app, gửi bộ đó một lần với `config_source: ui`.

## Từ AI agent

Công cụ MCP `get_coverage` trả về đúng báo cáo của trang — trạng thái, tỷ lệ và những gì thấy nhưng chưa khai báo — để coding agent kiểm tra tính năng vừa làm có thật sự đang gửi dữ liệu. Xem [MCP](https://belvador.dev/vi/docs/mcp).

## Những gì rời khỏi node

Cho độ phủ, node chỉ gửi khoá và thời điểm: môi trường, phần, tín hiệu, lần cuối thấy và lần cuối xác minh — không bao giờ gửi nội dung, tên, thuộc tính hay số lượng dữ liệu của bạn. Mỗi project giữ tối đa 256 khoá. Lần đầu một node có báo độ phủ khởi động, nó đọc lại một lần 30 ngày lỗi và check-in, 7 ngày trace và log, để app đang chạy không bắt đầu ở trạng thái chưa biết.

Độ phủ cần node 0.1.35 trở lên. Node cũ hơn không báo gì, và trang sẽ nói rõ điều đó thay vì đoán.
