Skip to content

[metrics][warehouse] 지표·등록 조회·검증 보고서의 공통 읽기 서비스를 제공하고 고정 snapshot에서 계산한다 #2862

Description

@kang-heewon

Priority / baseline

P1 — 지표 의미와 공통 읽기 서비스의 단일 소유자.
원 기준 2026-09-22 trunk@7dc3a10fb4bea30b667275e316b6e79971dde6c8; 재검토 trunk@c57ba6e287beeea183a0f393a9a5f61a4009f78e.

Purpose / ownership

fact 숫자 컬럼과 지표 의미를 분리하고 API·운영 UI·CLI/MCP·선택적 LLM UI에 동일한 검증 결과를 제공한다. 출발점은 packages/metrics-core/README.md, 기존 MetricsRepository/TimescaleMetricsStore이며 DB 구현은 #2872/PR #2875의 provider 경계를 따른다. 이관 전후 지표 버그가 자동 해결됐다고 하지 않는다.
VerifiedMetricCatalog/RegisteredQuery·권한/예산 read runner·검증 보고서 matching은 이 P1 작업이 소유한다. 이전 #2828의 해당 기반 구현 요구를 여기로 이동한다. #2852는 CLI/MCP transport, #2828(P3)은 자연어 계획/설명 UI만 추가한다. 어느 기반도 LLM 계정이나 P3 UI를 선행으로 요구하지 않는다. 새 평행 registry/범용 agent/SQL engine은 만들지 않는다.

Public contract / package boundary

metrics-core에 provider-neutral defineMetric·expression/result·catalog/read 계약을 둔다. SDK/SQL은 warehouse-postgres 등 provider, 서버 권한 실행은 적절한 runtime subpath다. browser-safe 선언에 DB/Node/React가 따라오지 않고 warehouse-core가 metrics 구현에 역의존하지 않게 최소 expression protocol의 소유권을 고정한다.
defineMetric('cash_received',{version:1,from:captures,measure:sum(captures.columns.amountMinor),groupByRequired:[captures.columns.currency],time:captures.columns.capturedAt})ratio({numerator:sum(clicks),denominator:sum(impressions),zeroDenominator:'null'})은 제안 API다. 수납을 회계상 매출로 자동 명명하지 않는다.
RegisteredQuery={id,version,inputSchema,outputSchema,definitionRefs,unit,population,readExecutor,limits}; Result={data,definitionId/version/hash,snapshotRefs,sourceRefs,window,population,numerator?,denominator?,quality,diagnostics}.

Common read service

  1. listDefinitions/getVerifiedReport/runRegisteredQuery/explainDefinition을 동일 서비스로 제공한다. 등록은 신뢰된 앱 코드만 가능하며 model/browser/tool input이 executor·SQL·credential·principal을 추가/변경하지 못한다.
  2. warehouse 외의 검증된 로컬 보고서/외부 reader도 연결 가능한 좁은 port를 제공한다. 해당 기본 read 경로에 PostgreSQL 서버 설치를 강제하지 않는다. verified 여부는 이름이 아니라 검수 metadata·실제 정의/결과로 판정한다.
  3. 보고서 matching은 definition version/hash, unit, population/filter, 기간, source revision, completeness, freshness, 현재 권한/privacy를 검사한다. 일치하는 보고서가 충분하면 추가 query를 실행하지 않는다. 부분 일치/권한 없음/stale는 명시 결과이며 임의 근사 보고서로 답하지 않는다.
  4. 매 invocation에 신뢰 principal/app/env/tenant·필드/원문 권한과 기간/row/byte/time/concurrency/cost capability·cancel을 적용한다. DB reader는 parameterized registered query와 read-only role 등 실제 경계를 사용한다. 함수명/SELECT 문자열 검사만으로 안전하다고 하지 않는다. audit는 query/source refs·시각·결과 상태만 bounded 보존한다.

Metric execution

  1. v1 기본 연산은 projection/filter/count/sum/min/max/exact-distinct, sum/count average, ratio, 명시 zone/date bucket이다. 타입/단위/null/재집계 의미를 검증하고 작은 JS reference와 실제 PG native compiler를 동일 fixture로 비교한다. 미지원 SQL을 전체 rows JS 다운로드로 숨기지 않는다.
  2. query 시작 시 [warehouse][postgres] 선언된 fact를 내구 적재·snapshot 게시·조회하고 Dataset Explorer에 연결한다 #2845 SnapshotSet을 고정하고 페이지/드릴다운에서 유지한다. 다중 source vector가 동시 관측을 의미하지 않는다. privacy/permission epoch는 시작뿐 아니라 결과/다음 페이지/cache 반환 때 검사하고 변경 시 폐기/재계산 또는 unavailable로 처리한다.
  3. quality는 freshness/temporalCompleteness/populationCoverage/validity/exactness/reproducibility로 나눈다. MAX(eventTime)·API final을 전체 관측으로 승격하지 않는다. 분모0·불완전·denied·unsupported·source error를 0/100%로 채우지 않는다.
  4. money는 currency filter/group 또는 시각/원천 있는 명시 FX를 요구한다. Int64/decimal은 wire decimal string으로 보존한다. [metrics-billing] Plan changes compare MRR amounts across currencies without conversion #2331 혼합 통화·[billing-core] Money.fromDecimal이 부동소수점 곱셈을 사용해 1.005 USD가 1.00으로 반올림된다 #2472 Money 정확성의 해당 회귀를 재사용한다. 구간은 [from,to), calendar는 IANA zone이다.
  5. 일별 distinct 합을 월 distinct로, percentile 평균을 전체 percentile로, 부분 상세를 총계로 만들지 않는다. exact 요청을 자동 approximate로 바꾸지 않는다. v1 cross-fact join은 거절하며 many-to-one dimension은 [warehouse][dimension] 시점 이력 dimension과 fact의 as-of many-to-one 연결을 선언한다 #2865 cardinality 검증 후 지원한다.
  6. cache identity는 definition/snapshots/parameters/principal permissions/privacy epoch를 포함한다. 작은 Metric Inspector가 같은 실제 field·분모·출처·quality를 렌더링한다. [warehouse-tooling] OLTP·fact·ETL·물리 binding을 한 구성에서 검증하고 형상관리 산출물을 생성한다 #2859/#2860에는 같은 graph node/dependency를 제공한다.

RUM extension ownership

#2849가 metric 갱신의 최신 유효 표본 선택과 quantile/분포의 제품 의미를 소유한다. raw update identity=(scope,pageInstance,metricId,revision), 분석 표본 identity=(scope,pageInstance,metricId)로 구분하고 latest revision 선택의 충돌/누락 규칙을 재사용한다.
RUM exact percentile과 latest-per-key의 native 실행이 필요하면 이 expression/compiler의 제한된 extension으로 한 번 추가한다. #2849가 method 및 golden fixture를 제공하고 provider가 같은 의미로 실행한다. 미구현 연산은 unsupported이며 별도 SQL runner/전체 #2868 엔진을 필수로 만들지 않는다. RUM 확장이 아직 없어도 위 기본 metric/read 서비스는 완료 가능하다.

Acceptance criteria

  • 실제 PG currency별 수납 합·CTR과 JS reference가 결과/분모/정밀도까지 일치한다.
  • LLM/자연어 UI 없이 registered query와 검증된 로컬 report read/matching이 실제 작동한다. API·Inspector·CLI 소비자가 같은 catalog/result/runner를 쓴다.
  • 같은 이름의 다른 정의/분모/기간/version·stale 보고서는 완전 답으로 채택되지 않고, 정확히 맞는 보고서는 query를 추가 실행하지 않는다.
  • mixed currency·큰 정수·분모0·DST·partial·미지원 join/quantile·SQL injection·budget·cancel을 명시한다.
  • concurrent head advance에도 pinned pagination을 유지하고 권한/삭제 epoch 변경은 반환/cache에서 차단한다.

Dependencies / boundaries

PG native metric integration에는 #2856/#2845가 실제 선행이다. 비-warehouse read service는 같은 패키지의 별도 경로로 먼저 쓸 수 있다. #2828/#2852 전체 구현은 선행이 아니며 필요한 계약을 해당 이슈에 복제하지 않는다. 공통 file decoding은 #2857, DB reader는 #2845가 소유하고 리텐션/실험 통계/재무 outcome의 제품별 공식은 각 기능에 남긴다.

Validation / completion

최신 AGENTS.md·exports·관련 PR/실제 scripts를 확인하고 별도 브랜치에서 작업한다. negative type/runtime·숫자 golden·report matching·read-only/budget/권한 fixtures, 임시 PG 실제 query·concurrency/privacy/cursor, UI/API 상태·public API/docs/catalog·관련 test/typecheck/build·pnpm check를 수행한다. changeset·native/standalone 예제·지원 연산을 포함해 커밋하고 브랜치/커밋·소유권/지원 범위·수행/미수행 검증을 보고한다. trunk 직접 push·수동 bump·publish·운영 분석/유료 scan/evidence 수집 금지. SQL optimizer/자유 SQL BI/범용 agent는 범위 밖이다.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1Priority 1 issuefeatureProduct feature or roadmap capability

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions