feat: add provider-usage-attribution-hot-path milestone and SDD

This commit is contained in:
toki 2026-07-29 17:36:10 +09:00
parent b77b7cdb10
commit 0ae225d781
3 changed files with 189 additions and 0 deletions

View file

@ -46,6 +46,10 @@ Phase를 가로지르는 실제 다음 작업 선택은 [전역 마일스톤 실
- 경로: [provider-resource-admission-ownership-alignment](../../archive/phase/operational-observability-provider-management/milestones/provider-resource-admission-ownership-alignment.md)
- 요약: 공유 provider의 capacity·long-context lease, 공통 queue policy, Node reconnect/offline fencing과 Control Plane snapshot을 정렬하고 local two-alias capacity-1 smoke까지 검증했다.
- [계획] Provider 기준 Usage Attribution Hot Path
- 경로: [provider-usage-attribution-hot-path](milestones/provider-usage-attribution-hot-path.md)
- 요약: OpenAI-compatible token usage를 실제 호출 provider·served model·실행 시도에 귀속하고, 명시적으로 같은 논리 모델로 승인된 group에서만 가상 model group 집계를 허용한다.
- [계획] Provider 부하 메트릭과 Live Queue Dashboard
- 경로: [provider-load-metrics-queue-dashboard](milestones/provider-load-metrics-queue-dashboard.md)
- 요약: provider별 capacity 사용률, in-flight, queue 적체, queue wait를 Prometheus time series와 Grafana dashboard로 노출해 시간대별 live 부하 분석을 가능하게 한다.

View file

@ -0,0 +1,80 @@
# Milestone: Provider 기준 Usage Attribution Hot Path
## 위치
- Roadmap: [ROADMAP.md](../../../ROADMAP.md)
- Phase: [PHASE.md](../PHASE.md)
## 목표
OpenAI-compatible hot path의 provider-reported token usage를 가상 요청 모델명이 아니라 실제 호출된 provider와 served model에 귀속한다. 가상 `model_group` 집계는 명시적으로 동일 논리 모델로 승인된 group에서만 허용하고, 단독·하이브리드·재시도/fallback 경로는 각 실제 호출 시도의 provider usage를 분리해 기록한다.
## 상태
[계획]
## 승격 조건
- 없음
## 구현 잠금
- 상태: 해제
- SDD: 필요
- SDD 문서: [SDD.md](../../../sdd/operational-observability-provider-management/provider-usage-attribution-hot-path/SDD.md)
- SDD 사유: OpenAI usage metric의 attribution contract, direct route provider identity, provider-pool retry/fallback의 시도별 관측과 Grafana query 기준을 함께 바꾼다.
- 잠금 해제 조건:
- [x] SDD 잠금이 해제되어 있다.
- [x] SDD 사용자 리뷰가 없거나 승인/해결되었다.
- [x] Acceptance Scenario가 Milestone 기능 Task와 연결되어 있다.
- [x] Evidence Map이 완료 시 `Roadmap Completion`과 최종 검증 evidence로 검증 가능하게 연결되어 있다.
- 결정 필요: 없음
## 범위
- provider-reported input/output/reasoning/cached-input token을 실제 `provider_id`와 served model에 귀속하는 OpenAI metric attribution contract
- `models[].usage_attribution=model_group`으로 명시 승인된 동일 논리 모델 group만 가상 model-group rollup을 허용하고, 기본값 `provider`를 적용하는 config/validation 기준
- direct/legacy route와 provider-pool hybrid route 모두에서 실제 provider identity를 dispatch 결과로 보존하는 경로
- retry/fallback을 포함한 각 실제 provider 호출 시도별 usage emission 및 저-cardinality label guard
- Grafana usage query와 운영 가이드의 provider 기준 migration
## 기능
### Epic: [attribution] Actual Provider Usage Attribution
단일·하이브리드 실행에서 token 사용량을 실제 provider 호출에 정확히 귀속하는 hot-path capability를 묶는다.
- [ ] [group-policy] `models[].usage_attribution=model_group`으로 명시 승인된 동일 논리 모델 group만 가상 rollup query를 허용하고, 기본값 및 그 밖의 route에는 provider 기준 attribution을 강제한다. 검증: group·direct·hybrid config/route test에서 attribution basis가 기대값과 일치하고 별도 group counter가 중복 emit되지 않는다.
- [ ] [dispatch-binding] direct/legacy의 `openai.model_routes[].provider_id`와 top-level fallback `openai.provider_id`, provider-pool의 normalized/tunnel dispatch가 실제 `provider_id`, served model, node identity를 metric emitter까지 전달한다. 검증: adapter 이름만으로 provider를 대체하지 않고 각 dispatch binding을 검증한다.
- [ ] [attempt-usage] hybrid selection, retry, fallback에서 provider-reported token 및 reasoning observation usage를 실제 호출 시도별 provider binding으로 emit한다. 검증: provider가 바뀌는 deterministic test에서 token series가 각 provider에 분리되어 증가하고 request terminal counter는 한 번만 증가한다.
### Epic: [operations] Usage Metric Migration
provider 기준 운영 조회를 기존 OpenAI usage metric과 Grafana 가이드에 정착시킨다.
- [ ] [metric-contract] metric label allowlist와 OpenAI-compatible 관측 계약을 provider attribution 기준으로 갱신하고 기존 `model_group``route_model` trace와 승인된 rollup query로 migration한다. 검증: secret/high-cardinality label guard와 metric contract test가 통과한다.
- [ ] [grafana-migration] Grafana query와 usage 운영 가이드를 provider 기준 집계 및 승인된 model-group rollup 기준으로 갱신한다. 검증: 대표 provider·group query가 metric label schema와 일치한다.
## 완료 리뷰
- 상태: 없음
- 요청일: 없음
- 완료 근거: 계획 Milestone이며 기능 Task가 아직 충족되지 않았다.
- 검토 항목: 기능 Task의 deterministic attribution 검증, Grafana query migration, SDD Evidence Map 충족과 구현 잠금 해제를 함께 확인한다.
- 리뷰 코멘트: 없음
## 범위 제외
- request ledger storage, 장기 retention, export API, billing/chargeback
- provider routing 알고리즘, capacity/queue timeout 정책 변경
- provider가 보고하지 않은 token의 추정 또는 billing-grade 복원
- Control Plane/Flutter client의 신규 usage 화면
## 작업 컨텍스트
- 관련 경로: `apps/edge/internal/openai`, `apps/edge/internal/service`, `packages/go/config`, `configs/edge.yaml`, `docs/openai-usage-grafana.md`, `agent-contract/outer/openai-compatible-api.md`
- 표준선(선택): canonical token attribution은 실제 dispatch provider binding이며, `model_group``models[].usage_attribution=model_group`으로 명시 승인된 동일 논리 모델의 query-time rollup에만 사용한다. 기본 attribution은 `provider`다.
- 표준선(선택): provider-pool 재시도/fallback은 client 응답이 하나여도 provider-reported usage가 있는 각 실제 호출 시도를 독립 provider series로 기록한다.
- 선행 작업: [Provider Resource Admission Ownership 정합화](../../../../archive/phase/operational-observability-provider-management/milestones/provider-resource-admission-ownership-alignment.md)
- 후속 작업: [Provider 부하 메트릭과 Live Queue Dashboard](provider-load-metrics-queue-dashboard.md), [요청 실행 로그와 Usage Ledger 기반](request-execution-log-usage-ledger-foundation.md)
- 확인 필요: 없음

View file

@ -0,0 +1,105 @@
# SDD: Provider 기준 Usage Attribution Hot Path
## 위치
- Milestone: [Milestone 문서](../../../phase/operational-observability-provider-management/milestones/provider-usage-attribution-hot-path.md)
- Phase: [PHASE.md](../../../phase/operational-observability-provider-management/PHASE.md)
## 상태
[승인됨]
## SDD 잠금
- 상태: 해제
- 사용자 리뷰: 없음
- 잠금 항목: 없음
## 문제 / 비목표
- 문제: 현재 OpenAI-compatible token counter는 provider-reported token 수를 받지만, 요청의 가상 `model_group`으로 귀속한다. 단독·하이브리드·재시도/fallback 실행에서는 실제 provider 사용량과 집계 series가 달라질 수 있다.
- 비목표:
- request ledger 저장, 장기 보관, export 또는 billing/chargeback 구현
- provider routing, queue admission, capacity 정책 변경
- provider가 보고하지 않은 token 수의 billing-grade 추정
## Source of Truth
| 영역 | 기준 | 메모 |
|------|------|------|
| Roadmap | [Milestone 문서](../../../phase/operational-observability-provider-management/milestones/provider-usage-attribution-hot-path.md) | 완료 Task와 검증 기준 |
| Code | `apps/edge/internal/openai/usage_metrics.go` | OpenAI request/token metric label과 emitter source of truth |
| Code | `apps/edge/internal/service/run_types.go` | actual dispatch의 provider/model binding source of truth |
| Contract | [OpenAI-compatible API 계약](../../../../agent-contract/outer/openai-compatible-api.md) | external model route와 OpenAI usage 관측 계약 |
| Config | `packages/go/config``configs/edge.yaml` | `models[].usage_attribution`, direct route `provider_id`와 fallback provider identity 기준 |
| User Decision | 현재 사용자 요청 | 동일 논리 model group만 virtual rollup, 그 밖의 실제 provider별·시도별 귀속을 사용한다. |
## State Machine
| 상태 | 진입 조건 | 다음 상태 | 근거 |
|------|-----------|-----------|------|
| route resolved | 요청 model의 group/direct route와 `usage_attribution`이 확정됨 | provider selected | OpenAI route resolution/config validation |
| provider selected | provider-pool candidate 또는 config가 검증한 direct provider binding이 확정됨 | provider usage observed / dispatch failed | `RunDispatch` 또는 tunnel dispatch binding |
| provider usage observed | 해당 실제 provider 호출이 token usage를 보고함 | emitted | provider binding별 metric emission |
| emitted | token series가 provider binding으로 기록됨 | provider selected / terminal | retry/fallback이면 새 실제 provider selection, 아니면 terminal |
| terminal | 모든 호출 시도가 종료됨 | 없음 | request terminal status metric |
## Interface Contract
- 계약 원문: [OpenAI-compatible API 계약](../../../../agent-contract/outer/openai-compatible-api.md)
- 입력:
- `route_model`: 외부 request `model` alias; routing trace용 값이며 canonical usage key가 아니다.
- `usage_attribution`: `models[].usage_attribution``model_group` 또는 `provider`; 기본값은 `provider`이며 `model_group`은 operator가 동일 논리 모델이라고 승인할 때만 설정한다.
- `provider_id`: 실제 dispatch한 globally unique provider resource identity
- `served_model`: 해당 provider가 실제 호출한 model target
- `usage`: 해당 provider 호출이 보고한 input/output/reasoning/cached-input token 수
- direct binding: `openai.model_routes[].provider_id` 또는 top-level fallback `openai.provider_id`; 둘 다 없으면 provider-attribution direct route config를 거부한다.
- 출력:
- canonical token/reasoning series: 실제 `provider_id`·`served_model`에 귀속된 provider-reported usage를 호출 시도마다 한 번 기록한다.
- 승인된 group rollup: `usage_attribution=model_group`인 series만 `route_model` 기준으로 PromQL에서 합산한다. 별도 group counter를 emit하지 않아 이중 집계를 막는다.
- request terminal counter: HTTP 요청당 한 번만 기록하며, provider별 token series의 호출 횟수 대용으로 사용하지 않는다.
- 금지:
- direct route의 provider identity를 `adapter` 이름만으로 대체하지 않는다.
- hybrid/retry/fallback 요청의 usage를 최초 또는 외부 request model에 단일 귀속하지 않는다.
- virtual model group용 token counter를 provider token counter와 별도로 emit해 같은 usage를 이중 집계하지 않는다.
- raw token, request/session id, prompt/response를 metric label에 넣지 않는다.
## Acceptance Scenarios
| ID | Milestone Task | Given | When | Then |
|----|----------------|-------|------|------|
| S01 | `group-policy` | `usage_attribution=model_group`으로 승인된 group과 기본 provider route | provider-reported usage가 수신됨 | 승인된 group만 query-time rollup이 가능하고, 모든 usage는 actual provider series 하나로 시작한다. |
| S02 | `dispatch-binding` | direct/legacy 또는 provider-pool route | dispatch가 성공함 | metric emitter가 adapter 대체값이 아닌 config/dispatch가 검증한 actual provider id와 served model을 받는다. |
| S03 | `attempt-usage` | hybrid request가 retry/fallback으로 다른 provider를 호출함 | 각 provider가 usage를 보고함 | 각 usage가 해당 실제 provider series에 한 번씩 기록되고 HTTP request counter는 한 번만 증가한다. |
| S04 | `metric-contract` | metric scrape와 OpenAI contract | label schema를 검증함 | secret/high-cardinality label 없이 provider attribution contract가 유지된다. |
| S05 | `grafana-migration` | provider·승인된 group series가 존재함 | 대표 Grafana query를 실행함 | provider 기준 집계와 허용된 group rollup이 모두 정확히 조회된다. |
## Evidence Map
| Scenario | Required Evidence | `agent-task` 연결 | 완료 Evidence 기대 |
|----------|-------------------|------------------|---------------------------|
| S01 | config/route table test와 provider series/group rollup metric delta assertion | `agent-task/m-provider-usage-attribution-hot-path/...` | `group-policy` Task id, test command와 PASS output |
| S02 | direct config provider ref, pool normalized·tunnel dispatch binding test | `agent-task/m-provider-usage-attribution-hot-path/...` | `dispatch-binding` Task id, provider id/served model assertion |
| S03 | deterministic retry/fallback provider switch test와 request counter assertion | `agent-task/m-provider-usage-attribution-hot-path/...` | `attempt-usage` Task id, provider별 token series delta와 request counter 1회 |
| S04 | `go test ./apps/edge/internal/openai`와 metric label guard | `agent-task/m-provider-usage-attribution-hot-path/...` | `metric-contract` Task id, command output |
| S05 | Grafana guide/query schema check | `agent-task/m-provider-usage-attribution-hot-path/...` | `grafana-migration` Task id, query evidence |
## Cross-repo Dependencies
- 없음
## Drift Check
- [x] Milestone 기능 Task와 Acceptance Scenario가 일치한다.
- [x] Evidence Map이 code-review/complete.log에서 검증 가능하다.
- [x] agent-contract를 쓰는 경우 SDD에 계약 원문을 복제하지 않았다.
- [x] 사용자 리뷰가 필요한 항목은 `USER_REVIEW.md`에만 남겼다.
## 사용자 리뷰 이력
- 없음
## 작업 컨텍스트
- 표준선: `models[].usage_attribution`의 기본값은 `provider`다. 동일 논리 model group이라고 operator가 명시 승인한 경우에만 `model_group`을 설정하고, canonical usage attribution은 항상 actual provider binding에서 출발한다.
- 후속 SDD: 없음