# 서비스, OFAC 데이터셋, 응답의 서명은 어떻게 모니터링합니까?

오류, 한도, 신뢰 · 프로세스 가동 상태, 제재 목록의 경과 시간과 개수, 서비스 자체의 예산 — 그리고 서명하는 배포가 모든 응답에 덧붙이는 Ed25519 증명(attestation)

*API 가이드 · 7분 · 중급 · 개발자 · GET /health · /ready · /v1/sanctions · /v1/stats/slo · POST /v1/verify-attestation*

체인이 아니라 서비스를 감시하는 조회가 네 가지 있습니다. `/health`와 `/ready`는 프로세스 가동 상태 — 실행 중이며 데이터베이스가 응답함 — 이며, 인덱싱에 대해서는 아무것도 말하지 않습니다. `GET /v1/sanctions`는 OFAC 데이터셋입니다. 생태계별 개수(2026-10-24에 주소 385개: EVM 120, 트론 261, 솔라나 4)와 `updated_at`이 있습니다. `GET /v1/stats/slo?chain=`은 서비스의 지연 시간 예산과 배치 기준점 — OFAC 목록, 주간 그래프 배치 — 의 경과 시간입니다. 그리고 응답에 서명하는 배포는 응답에 `attestation` 객체를 덧붙입니다. `POST /v1/verify-attestation`은 본문을 그것과 대조해 확인하며, 무료이고 독립적입니다. 이 배포는 현재 서명하지 않으며, `/.well-known/jwks.json`은 비어 있습니다.

## 가동 상태

```
curl -s https://stablescan.achivx.com/health    # {"status": "ok"}
curl -s https://stablescan.achivx.com/ready     # {"status": "ready"}, or 503 not_ready
```

둘 다 `no-store`입니다. *프로세스가 실행 중*이고 *데이터베이스가 응답한다*고 답합니다. 둘 다 예라고 답하는 동안에도 네트워크는 몇 시간 뒤처져 있을 수 있습니다. 최신성은 네트워크별 [`/v1/sync/status?chain=`](https://achivx.kr/academy/api/sync-status/)이며, *데이터가 최신인가*에 맞는 확인 수단입니다.

## 제재 데이터셋

```
curl -s https://stablescan.achivx.com/v1/sanctions
```

```
{
  "source": "ofac_sdn",
  "evm_count": 120,
  "solana_count": 4,
  "tron_count": 261,
  "total": 385,
  "updated_at": "2026-10-24T04:00:04Z",
  "note": "OFAC SDN digital-currency addresses (public, 0xB10C list). Heuristic exposure only — not legal advice; verify against the official SDN list."
}
```

`updated_at`은 모든 판정이 `sanctions_list_as_of`로 반복하는 날짜입니다. 목록이 7일보다 오래되면 깨끗한 판정이 `ofac_list_stale`과 함께 `unknown`으로 읽힙니다. 주소 목록 내보내기는 없습니다. 등재 여부는 [주소 개요](https://achivx.kr/academy/api/address-overview/)의 `sanctioned`입니다. `max-age=300`이며, ETag로 재검증됩니다.

## 서비스 자체의 예산

```
curl -s 'https://stablescan.achivx.com/v1/stats/slo?chain=1'
```

```
{
  "chain_id": 1, "chain_source": "explicit",
  "latency": [
    {"class": "verify_attestation", "budget_ms": 50,  "observed_p95_ms": 0,    "samples": 0,   "within_budget": true},
    {"class": "ego_graph",          "budget_ms": 800, "observed_p95_ms": 4707, "samples": 148, "within_budget": false},
    {"class": "cached_aggregate",   "budget_ms": 300, "…": "…"}
  ],
  "freshness": [
    {"anchor": "ofac_sanctions", "scope": "global", "known": true, "age_seconds": 24519,  "budget_seconds": 86400,  "within_slo": true, "last_refresh": "2026-10-24T04:00:04Z"},
    {"anchor": "graph_batch",    "scope": "chain",  "known": true, "age_seconds": 530664, "budget_seconds": 691200, "within_slo": true, "last_refresh": "2026-10-18T07:24:18Z"}
  ],
  "signal_firing": [{"detector": "wash", "scope": "chain", "known": true, "count": 0}, {"detector": "inflation", "…": "…"}, "…"],
  "as_of": "2026-10-24T10:48:43Z"
}
```

`latency[]`는 경로 유형별 최근 프로세스 내 p95를 공개된 예산과 비교한 것입니다(`samples: 0` = 아직 관측되지 않음). 그날 아침 에고 그래프는 p95 4.7초로 800 ms 예산을 초과했으며, 무거운 주소에서의 `202 building`이 여기서는 이렇게 보입니다. `freshness[]`는 각 배치 기준점의 경과 시간입니다. [OFAC](https://achivx.kr/academy/how-it-works/what-is-the-ofac-sdn-list/) 목록(전역, 하루 예산)과 주간 그래프 배치(체인별, 8일 예산 — 최근 주간 실행보다 오래된 `last_refresh`는 해당 체인의 실행이 반영되지 않았다는 뜻)입니다. 한 체인에 대해 응답합니다. `chain`을 넘기거나, 그렇지 않으면 `chain_source: "default"`가 베이스(Base)임을 알려 줍니다. `no-store`: 모든 조회는 실시간입니다.

[첫 번째 요청](https://achivx.kr/academy/api/first-request/)의 헬퍼 세 개로 한 같은 호출:

**Python**

```
slo = scan("/v1/stats/slo", chain=1)
late = [l["class"] for l in slo["latency"] if l["samples"] and not l["within_budget"]]
stale = [f["anchor"] for f in slo["freshness"] if not f["within_slo"]]
sanctions = scan("/v1/sanctions")
print("over budget:", late, "| stale anchors:", stale, "| OFAC list:", sanctions["total"], "addresses as of", sanctions["updated_at"])
```

**Go**

```
var slo struct {
	Latency []struct {
		Class        string `json:"class"`
		Samples      int    `json:"samples"`
		WithinBudget bool   `json:"within_budget"`
	} `json:"latency"`
	Freshness []struct {
		Anchor     string `json:"anchor"`
		AgeSeconds int    `json:"age_seconds"`
		WithinSLO  bool   `json:"within_slo"`
	} `json:"freshness"`
}
if err := get("/v1/stats/slo", url.Values{"chain": {"1"}}, &slo); err != nil {
	return err
}
```

**TypeScript**

```
type Slo = {
  chain_id: number; chain_source: "explicit" | "default";
  latency: { class: string; budget_ms: number; observed_p95_ms: number; samples: number; within_budget: boolean }[];
  freshness: { anchor: string; scope: "global" | "chain"; known: boolean; age_seconds: number; budget_seconds: number; within_slo: boolean; last_refresh: string }[];
  as_of: string;
};
const slo = await scan<Slo>("/v1/stats/slo", { chain: 1 });
const sanctions = await scan<{ total: number; updated_at: string }>("/v1/sanctions");
```

## 증명: 서명된 응답

서명하는 [배포](https://achivx.kr/academy/reference/glossary/#g-deployment)는 모든 주소 응답에 `attestation` 객체를 덧붙입니다. [OpenAPI](https://achivx.kr/academy/reference/api-methodology/) 스키마는 개요, risk, exposure, approvals, balances, heuristics에서 이를 설명합니다: *an Ed25519 signature over the JCS-canonical body without this field*(이 필드를 제외한 JCS 정규화 본문에 대한 Ed25519 서명). `alg`, `kid`, `method`, `observed_hash`, `ruleset_version`, `data_vintage`, `signed_at`, `sig`가 있습니다. 확인 방법은 두 가지입니다.

- `/.well-known/jwks.json`의 공개 키로 오프라인 확인 — 본문을 정규화하고(RFC 8785, `attestation` 제외), 해시한 뒤, `kid`가 가리키는 키로 `sig`를 검증합니다.
- 또는 본문과 그 [증명](https://achivx.kr/academy/issuers/what-is-a-reserve-attestation/)을 `POST /v1/verify-attestation`으로 보냅니다. 서버가 해시를 다시 계산해 `{"valid": true|false, "alg", "kid", "observed_hash"}`로 응답하며, `valid`가 false이면 `reason`을 덧붙입니다 — *false is an answer, not an error: the body was altered, the signature does not verify, or the algorithm is not Ed25519. HTTP stays 200.*(false는 오류가 아니라 답입니다: 본문이 변경되었거나, 서명이 검증되지 않거나, 알고리즘이 Ed25519가 아닙니다. HTTP는 200으로 유지됩니다.) 자신의 키로 확인하려면 `public_key`(base64url 원시 Ed25519 키)를 넘기십시오.

**이 배포는 현재 서명하지 않습니다.** 2026-10-24에 어떤 주소 응답에도 `attestation`이 없었고, [`/v1/methodology`](https://stablescan.achivx.com/v1/methodology)에도 없었으며, `/.well-known/jwks.json`은 `{"keys": []}`로 응답했고, 본문과 증명을 넣은 `POST /v1/verify-attestation`은 `400 no_key`로 응답했습니다 — *no public_key supplied and this deployment has no signing key*(public_key가 제공되지 않았고 이 배포에는 서명 키가 없습니다). 잘못된 형식의 키는 `400 invalid_public_key`, 두 부분이 없는 본문은 `400 invalid_body`(*body and attestation are required*)입니다. `attestation`이 없는 응답을 *무효*가 아니라 *서명 없음*으로 처리하도록 확인 코드를 작성하면, 키가 설정되는 날에도 올바르게 동작합니다.

```
def attested(answer):
    '''None when the deployment does not sign; True/False from the server's check otherwise'''
    att = answer.get("attestation")
    if not att:
        return None
    body = {k: v for k, v in answer.items() if k != "attestation"}
    req = urllib.request.Request(BASE + "/v1/verify-attestation", method="POST", data=json.dumps({"body": body, "attestation": att}).encode(),
                                 headers={"Content-Type": "application/json", "Accept": "application/json"})
    with urllib.request.urlopen(req, timeout=30) as r:
        return json.load(r)["valid"]
```

## 무엇에 대해 알림을 보낼 것인가

- `/ready`가 1분 동안 `200`이 아님: 데이터가 아니라 서비스 문제입니다.
- 의존하는 네트워크에서 `/v1/sync/status`의 `freshness_seconds`가 임계값을 넘음: 데이터 문제입니다.
- `/v1/sanctions`의 `updated_at`이 하루보다 오래됨: [OFAC](https://achivx.kr/academy/how-it-works/what-is-the-ofac-sdn-list/) 기준점(`/v1/stats/slo`의 `ofac_sanctions` 행에서 `within_slo: false`와 같습니다).
- `graph_batch`가 예산 초과: [거래 상대 그래프](https://achivx.kr/academy/guides/counterparty-graph/)가 오래되고 있습니다. `/graph` 응답에 `snapshot_age_seconds`로 나타납니다.

## Stablecoin scanner ACHIVX에서

- [/health](https://stablescan.achivx.com/health), [/ready](https://stablescan.achivx.com/ready), [/v1/sanctions](https://stablescan.achivx.com/v1/sanctions), [/v1/stats/slo?chain=1](https://stablescan.achivx.com/v1/stats/slo?chain=1), [/.well-known/jwks.json](https://stablescan.achivx.com/.well-known/jwks.json).
- 사이트에 표시되는 [OFAC](https://achivx.kr/academy/how-it-works/what-is-the-ofac-sdn-list/) 상태: 등재된 주소의 빨간 배너, [/ethereum/address/0x098B…2f96](https://stablescan.achivx.com/ethereum/address/0x098B716B8Aaf21512996dC57EB0615e2383E2f96).

## 출처

- [REST 인터페이스의 OpenAPI 3.1 명세(API 1.4.0)](https://stablescan.achivx.com/openapi.json)
- [에이전트 매뉴얼 — agents.md(버전 2026-10-05)](https://stablescan.achivx.com/agents.md)
- [GET /v1/stats/slo?chain=1(2026-10-24 조회)](https://stablescan.achivx.com/v1/stats/slo?chain=1)
- [GET /v1/sanctions(2026-10-24 조회)](https://stablescan.achivx.com/v1/sanctions)

## 더 알아보기

- [get-sanctions-status는 무엇을 반환합니까?](https://achivx.kr/academy/for-agents/get-sanctions-status/)
- [숫자는 어떻게 만들어지며, 누가 서명합니까?](https://achivx.kr/academy/for-agents/how-the-numbers-are-produced-and-signed/)
- [집계 범위와 최신성](https://achivx.kr/academy/concepts/coverage-and-freshness/)

## 관련 질문

- [지금 네트워크의 데이터는 얼마나 최신입니까?](https://achivx.kr/academy/api/sync-status/)
- [코드에서 오류, 요청 한도, 타임아웃을 처리하려면 어떻게 합니까?](https://achivx.kr/academy/api/errors-and-limits-in-code/)
- [주소에 대한 위험 판정 하나를 얻으려면 어떻게 하며, 언제 unknown이 됩니까?](https://achivx.kr/academy/api/address-risk/)

오류, 한도, 신뢰 · GET /health · /ready · /v1/sanctions · /v1/stats/slo · POST /v1/verify-attestation · 2026-10-24 작성, openapi.json, agents.md 및 당일 실제 호출 기반. 구조는 인용한 것이며, 수치는 날짜 기준이고 인덱스에 따라 바뀝니다.

---

출처: https://achivx.kr/academy/api/service-status-and-attestations/ · 영어 원문: https://achivx.com/academy/api/service-status-and-attestations.html
