Skip to content

[Pricing] missing pricing·explicit zero와 pricing snapshot 정책 구현 #28

Description

@HuitaePark

문제

현재 가격 정보 누락을 무료 가격과 구분하기 어렵다.

  • PricingRegistry.getPlan(modelId)는 미등록 모델에 Optional.empty()를 반환한다.
  • DefaultLedgerAdvisor.after()는 plan이 없으면 비용 누적을 조용히 건너뛴다.
  • PricingPlan.getRate()는 fallback rate까지 없으면 BigDecimal.ZERO를 반환한다.
  • 따라서 무료 모델과 설정 누락이 모두 0원처럼 보일 수 있다.
  • 요청 도중 registry가 변경되면 reservation과 actual 정산이 서로 다른 가격을 사용할 수 있다.

budget notification lifecycle은 이 이슈에서 분리하여 #48이 담당한다.

목표 계약

explicit zero price != missing price

typed resolution 예시:

PricingResolution
├─ RESOLVED
├─ MISSING_PLAN
├─ MISSING_RATE
└─ CURRENCY_MISMATCH

budget/preflight control이 활성화된 경로의 기본값은 FAIL_CLOSED다. ledger-only 경로는 명시적 FAIL_OPEN을 허용할 수 있지만 missing을 0원 actual cost로 기록하지 않는다.

구현 범위

Typed pricing resolution

  • missing plan/rate를 결과 타입 또는 구조화 예외로 표현한다.
  • 명시적으로 등록된 0 rate는 정상 무료 가격으로 유지한다.
  • REASONING→COMPLETION, CACHE→PROMPT fallback은 원본 rate가 명시적으로 존재할 때만 허용한다.
  • 최종 fallback이 없으면 0이 아니라 MISSING_RATE다.
  • currency mismatch를 별도 결과로 표현하고 상태를 바꾸지 않는다.
  • FAIL_OPEN/FAIL_CLOSED 정책과 적용 경계를 configuration에 둔다.

Canonical model과 snapshot

  • [Core] versioned ModelRegistry와 최소 모델 정책 등록 #32 ModelRegistry alias는 canonical model id를 반환한다.
  • pricing lookup은 raw alias가 아니라 canonical model과 pricingPolicyId를 사용한다.
  • provider 호출 전에 plan을 한 번 resolve한다.
  • reservation에 다음 immutable snapshot을 보존한다.
    • canonical model id
    • pricingPolicyId와 version/catalogVersion
    • sourceAsOf/checkedAt
    • currency
    • 실제 적용 rate
  • registry가 호출 중 변경되어도 actual reconciliation은 예약 시 snapshot을 사용한다.
  • response model이 다른 canonical model로 바뀌면 명시적 정책에 따라 새 resolution 또는 RECONCILIATION_REQUIRED로 처리한다.

정책별 동작

  • FAIL_CLOSED: provider 호출 전에 구조화된 reason으로 차단하고 invocation count는 0
  • FAIL_OPEN: provider 호출은 허용하지만 UNPRICED signal을 남기며 0원으로 정산하지 않음
  • explicit zero: 정상 RESOLVED 결과와 0원 cost
  • missing price는 [Core] 보수적 PreflightCostBound 계산 계약과 구현 #45 CostBound 생성 실패로 전파한다.

필수 테스트

  • 미등록 plan은 MISSING_PLAN이다.
  • token type rate 누락은 MISSING_RATE다.
  • 명시적 0 rate는 RESOLVED zero cost다.
  • 명시적 base rate가 있을 때만 reasoning/cache fallback이 동작한다.
  • FAIL_CLOSED에서 provider 호출 횟수가 0이다.
  • FAIL_OPEN은 호출되지만 0원 actual로 기록되지 않는다.
  • alias와 canonical model이 동일 pricing policy snapshot을 사용한다.
  • registry 변경 후에도 in-flight 요청은 기존 snapshot으로 reconcile한다.
  • currency mismatch는 상태 무변경으로 실패한다.
  • pricing miss reason을 metric/event가 low-cardinality 값으로 식별할 수 있다.

Acceptance criteria

제외 범위

의존관계

Source

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestmvpTokenPilot 0.1.0 MVP scope

    Type

    No type

    Projects

    Status
    Todo

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions