11. JAM Metrics 버전 관리
메트릭 집합(어떤 지표를 재는가)과 산출식(어떻게 점수가 되는가)은 CLI 도구와 별개의 변경 주기를 가진다 — 산출식 개선, 임계값 보정, 새 지표 추가가 빈번할 것이기 때문이다. 따라서 JAM Metrics Spec을 CLI와 독립적으로 버전 관리한다.
1. 두 개의 버전
| 버전 | 대상 | 예 |
|---|---|---|
CLI 버전 (jam vX.Y.Z) | 실행파일: 성능, 파서, 출력 포맷, 버그 수정 | jam v0.46.0 |
Metrics Spec 버전 (metrics vX.Y.Z) | 메트릭 집합 + 산출식 + 임계값 + 비용 + 가중치 + 등급 컷 | metrics v14.5.0 |
하나의 CLI 릴리스는 정확히 하나의 Metrics Spec을 내장한다(임계값의 사용자 오버라이드는 스펙 버전과 무관 — 리포트에 "사용자 설정 적용됨"으로 별도 표기).
2. Metrics Spec의 SemVer 규칙
판정 기준은 단 하나: 같은 코드를 스캔했을 때 점수 비교 가능성(comparability)이 유지되는가.
| 변경 | 버전 | 이유 |
|---|---|---|
| 기존 메트릭의 산출식 변경 | MAJOR | 동일 코드의 점수가 달라짐 — 시계열 비교 단절 |
| 기존 메트릭의 기본 임계값/비용 변경 | MAJOR | 〃 |
| 카테고리 가중치, TDR_max, 등급 컷, cap·분모·score scope 규칙 변경 | MAJOR | 〃 |
| 메트릭 제거(폐기) | MAJOR | 〃 |
| 새 메트릭/언어 룰 추가로 기존 코드의 debt·점수·등급이 변함 | MAJOR | 시계열 수치 비교가 끊김 |
새 정보성 필드/메트릭(debt_counted=0)이나 기존 코드 점수가 불변임을 독립 holdout으로 입증한 커버리지 확장 | MINOR | 점수 비교 가능성 유지, 기능 추가 |
| 메시지/문서/출력 포맷 수정, 점수·finding set 불변 버그 수정 | PATCH | 측정값 비교 가능성 유지 |
| 오탐/미탐 수정으로 finding/debt/점수가 변함 | MAJOR | "더 정확"해도 과거 수치와는 동일 측정 계열이 아님 |
jam diff는 CSV의 finding_id로 added/fixed/unchanged를 계산하기 전에 양쪽 jam-run.json을 검증한다. 현재는 보수적으로 정확히 같은 CLI 버전, Metrics Spec, policy hash, effective configuration hash와 integrity=complete를 요구한다. 이 조건은 스펙 MAJOR만 같으면 된다는 약한 규칙보다 엄격하며, 구 baseline은 --allow-incompatible로만 명시적으로 우회한다.
3. 단일 진실 공급원 (Single Source of Truth)
internal/metrics/registry.go ← 코드: 전체 메트릭 정의 (ID, 이름, 카테고리, 임계값,
비용, 도입 버전 since, 개별 산출식 버전 version, 문헌 근거)
internal/metrics/spec.go ← 코드: SpecVersion 상수, 카테고리 가중치, TDR_max, 등급 컷
docs/metrics-changelog.md ← 문서: Spec 버전별 변경 이력 (사람용)
docs/02-metrics-catalog.md ← 문서: 메트릭의 정의·근거 (레지스트리와 ID로 1:1 대응)
- 레지스트리의 각 메트릭은
Since(도입된 spec 버전)와Version(그 메트릭의 산출식 버전, 정수)을 가진다. 산출식이 바뀌면 메트릭Version++ 와 Spec MAJOR++가 함께 일어난다. jam metrics명령으로 내장 스펙 전체(버전 포함)를 조회할 수 있다.- CI 게이트: 레지스트리 변경 PR은
docs/metrics-changelog.md변경을 동반해야 한다(검사 스크립트).
4. 산출물에의 기록
모든 산출물이 자신이 어떤 스펙으로 계산되었는지 스스로 말해야 한다:
| 산출물 | 기록 |
|---|---|
jam-report.md | 머리말에 jam v0.46.0 · metrics v14.5.0. 부록 A에 category coverage, 부록 C에 메트릭별 version |
jam-detail.csv | 행별 metric_version, debt_minutes, debt_counted, score_exclusion — 점수 산입과 범위 제외를 함께 추적 |
jam-result.json v3 | "metricSet": "jam-lite", "metricsSpec": {"version": "14.5.0"}, production scope·category coverage·assessment status |
jam-run.json @2 | CLI/Metrics Spec, policy/configuration hash, scope, role CLOC, category coverage, source hash, Git commit/tree/dirty, integrity, comparison key |
jam-full.json | "metricSet": "jam-full"과 컴포넌트별 점수. metrics spec은 jam-lite 컴포넌트에 적용 |
jam.sarif | rules[].properties.metricsSpec, results[].properties.metricsSpec, metric별 version/threshold |
finding_id | 메트릭 버전·절대 라인 번호를 포함하지 않음. 파일+심볼/원본 메시지/소스 앵커 지문으로 관계없는 라인 이동에 안정 |
사용자 설정으로 임계값을 오버라이드해도 내장 Metrics Spec 버전은 바뀌지 않는다. 대신 CSV finding의 threshold, report 부록 C, SARIF rule properties에 해당 실행에서 적용된 임계값이 기록된다.
5. 폐기(Deprecation) 절차
- MINOR 릴리스에서
Deprecated: true표기 → 계속 측정되지만 리포트에 폐기 예고 표시, debt는 산입 유지. - 다음 MAJOR 릴리스에서 제거. 레지스트리에서 ID는 영구 결번(재사용 금지 — 과거 CSV와의 충돌 방지).
6. 구현에 미치는 영향 요약
- 메트릭 정의(임계값·비용·버전)는 분석기 코드에 하드코딩하지 않고 레지스트리에서 조회한다. 분석기는 측정값만 내고, 심각도 판정은 레지스트리 임계값으로 한다.
- 점수 엔진(가중치·등급 컷)도 spec.go 상수만 참조한다 — 산출식 변경이 한 파일의 diff로 보이게.
- 현재 metrics v14.5.0은 registry의 43개 메트릭이 모두
Implemented: true이다. 언어/카테고리 미적용은not_assessed,score_exclusion, 런 매니페스트의 category coverage로 별도 기록한다.