Reference

12. JAM Lite / Full 지표 세트

jam-lite와 jam-full의 경계, 외부 CLI orchestration, 합성 점수

Source: docs/12-jam-lite-full.md

12. JAM Lite / Full 지표 세트

JAM은 두 가지 점수를 제공한다.

1. jam-lite

jam scan의 기본값이며 jam lite와 같다.

측정 범위:

영역담당
크기SIZE-01~04
복잡도CPLX-01~05
아키텍처/결합ARCH-01~09
중복DUP-01~02
명백한 보안 패턴SEC-01~08
리소스/상태RES-01~03
코드 위생HYG-01~12

metrics v14.5.0 기준 registry의 jam-lite 43개 메트릭은 모두 구현되어 있다. CPLX-04/05, ARCH-02, DUP-02의 비-Go 경로는 경량 lexer 기반 휴리스틱이며 confidence는 medium 중심이다. 반면 타입 내부 구조가 필요한 ARCH-07/08, SIZE-04와 TS/JS SEC-07/08 taint 경로는 임베드 tree-sitter WASM을 사용한다. 점수는 category×language eligible production CLOC만 분모로 쓰고, test/docs/config/generated와 미지원 언어 finding은 감사 출력에 보존하되 점수에서 제외한다.

jam-lite는 “이 코드 위에 계속 쌓아도 되는가”에 대한 정적 신호다. 테스트 통과, 실제 커버리지, 의존성 취약점, 컨테이너/IaC 보안, 라이선스, 릴리스 산출물 검증은 jam-lite의 범위가 아니다.

2. jam-full

jam scan --set full 또는 jam full로 실행한다. full 모드는 먼저 jam-lite를 실행한 뒤, 같은 대상에 대해 외부 도구를 호출한다.

jam scan . --set full --out reports/jam

# alias
jam full . --out reports/jam

# security-only full gate
jam full . --component security --out reports/jam-security

# 별도의 전체 Git 이력 secret 감사(기본은 working tree)
jam full . --component security --security-history --out reports/jam-security-history

외부 도구 해석 순서:

  1. CLI 플래그: --test-cli, --security-cli, --spec-cli
  2. PATH의 test-cli, security-cli, spec-cli
  3. 개발 환경 fallback: ~/git/test-cli, ~/git/security-cli, ~/git/cli/security-cli, ~/git/spec-cli

v0.40 호환성 기준:

companion권장 최소읽는 계약하위호환
test-cli0.3.0test-cli/report@2 + quality/comparison/history/changesreport@1 허용, TEST-QUALITY=not_assessed
security-cli0.3.0schema 1 + security_status/coverage/scanners/targets/baselinev0.1 legacy 허용, SEC-COVERAGE=not_assessed
spec-cli0.2.0schema 1 spec-report + 원자적 spec-trace/spec-summaryv0.1 report-only 허용, SPEC-TRACE-GATE=not_assessed

test/security v0.3은 JAM이 읽는 계약 버전을 바꾸지 않고 Rust/Python runner 판정과 Gitleaks 기본 범위를 보정한 호환 릴리즈다. 알 수 없는 schema는 forward-compatible하게 추측하지 않고 report_invalid로 거부한다. producer가 필드를 바꿨는데 JAM이 예전 의미로 조용히 채점하는 것보다 fleet gate가 명시적으로 실패하는 편이 안전하다.

생성 파일:

파일내용
jam-report.mdjam-lite 사람용 리포트
jam-detail.csvjam-lite finding 원본
jam-run.json도구/스펙/정책/범위/Git/완전성 런 매니페스트
jam-full-report.mdfull 컴포넌트 요약
jam-full.jsonfull 합성 점수 JSON
test/report.jsontest-cli 표준 JSON
security/security-report.jsonsecurity-cli 표준 JSON
spec/spec-report.jsonspec-cli 요구사항 검증 계약(opt-in)
spec/spec-trace.jsonspec-cli 추적성 진단 원본(opt-in, v0.2)
spec/spec-summary.jsonspec-cli verification+trace gate 요약(opt-in, v0.2)

--component test, --component security, --skip-test, --skip-security로 full 외부 컴포넌트를 부분 실행할 수 있다. 부분 full에서는 선택된 컴포넌트만 componentsartifacts에 기록하고, 가중치는 선택된 기본 가중치 합이 1.0이 되도록 재정규화한다.

포트폴리오 기본 실행에서 security-cli의 Gitleaks는 working tree만 검사한다. 이는 오래된 대형 Git 이력 때문에 리포지토리별 실행 시간이 무제한으로 늘어나는 것을 막는다. 별도의 이력 감사에는 --security-history를 사용하며, JAM은 이를 security-cli의 --gitleaks-history로 전달한다. security 원본 리포트의 scanners[].modeworktree|history를 기록하므로 감사 증적에서 범위를 구분할 수 있다.

3. full 점수 합성

초기 가중치:

컴포넌트기본 가중치산출 근거
jam-lite0.50JAM 자체 정적 코드 건강도
test0.25test-cli의 테스트 실행, 커버리지, 증거 강도
security0.25security-cli의 보안 finding, 정책, 공급망/스캐너 상태
lint (opt-in)0.15외부 린터(ruff 등) finding — --component lint로만 활성. §3.2b
spec (opt-in)0.15외부 spec-cli 요구사항 검증 결과 — --component spec으로만 활성. §3.2c

lint와 spec은 기본 all에 포함되지 않는다(하위호환). 활성 시 위 가중치 집합에 각 0.15가 더해져 활성 컴포넌트 합이 1.0이 되도록 재정규화된다(예: lite+lint만 실행 시 lite 0.77 / lint 0.23).

production 코드가 없어 jam-lite가 Grade N/A이면 full의 lite 컴포넌트도 status=not_assessed, effective weight 0으로 기록한다. 측정 불가를 0점으로 합성하지 않고, 실제 측정된 외부 컴포넌트가 있으면 그 컴포넌트들끼리 재정규화한다.

부분 실행 예:

실행effective weight
기본 fulljam-lite 0.50, test 0.25, security 0.25
--component securityjam-lite 0.667, security 0.333
--component testjam-lite 0.667, test 0.333
--component lintjam-lite 0.77, lint 0.23
--component specjam-lite 0.77, spec 0.23
--component all,lintjam-lite 0.435, test 0.217, security 0.217, lint 0.13

3.1 test 컴포넌트 하위 지표

test-cli/report@1|@2test.summary, test.suites, coverage.summary, coverage.files를 읽어 다음 하위 지표로 분해한다. report@2에서는 canonical quality와 비교·추세·changed-line 데이터를 추가로 읽는다.

ID가중치목적산출식
TEST-PASS0.25실행된 테스트가 실제로 green인지 확인passed / (total - skipped) × 100
TEST-LINE-COV0.20실행 테스트가 코드 라인을 얼마나 덮는지 확인coverage.summary.lines.pct
TEST-BRANCH-COV0.12조건/분기 경로 커버리지 확인coverage.summary.branches.pct; 미제공 시 not_assessed
TEST-EVIDENCE0.10report가 요약뿐 아니라 suite/file 증거까지 갖는지 확인tests+coverage+suites+files=100, aggregate-only=85, tests-only=70, coverage-only=50
TEST-COV-TAIL0.08평균 뒤에 숨은 저커버리지 파일 감지커버리지 파일 중 최저 5개 라인 커버리지 평균; per-file 미제공 시 not_assessed
TEST-DENSITY0.12큰 코드 표면을 소수 smoke test가 과대평가하지 못하게 함실행 테스트 수 / coverable KLOC, 5 tests/KLOC 이상 100점
TEST-SOURCE-COV0.10coverage가 문서/설정이 아니라 소스 파일을 덮는지 확인coverage.files의 source line 비율; 확장자를 우선 판별
TEST-SKIP-RISK0.02skipped test가 많은 리포트 감지100 - skipped_ratio×2
TEST-DURATION-TAIL0.01느린 테스트 tail 감지test case duration p95, 1s 이하 100점, 10s 이상 0점
TEST-QUALITY0.00report@2의 canonical QA assessment와 증적 보존quality.score; 최종 test 점수의 상한. report@1은 not_assessed

not_assessed 하위 지표는 해당 언어/도구가 값을 제공하지 않은 경우이며, test 컴포넌트 내부 가중치 합산에서 제외하고 남은 지표 가중치를 재정규화한다. 테스트 실패나 에러가 있으면 test 컴포넌트 점수는 최대 50점으로 제한한다. 실행 테스트가 0개면 coverage가 있어도 no_test_evidence 품질 실패로 기록하고 최대 40점으로 제한한다. TEST-DENSITY가 큰 coverable surface에서 20점 미만이면 최대 70점으로 제한하고 품질 실패로 기록한다. TEST-SOURCE-COV가 큰 coverable surface에서 20점 미만이면 문서/설정 coverage 과대평가로 보고 test 컴포넌트 점수를 최대 50점으로 제한한다. report@2의 최종 값은 여기에 min(score, quality.score)를 적용한다. TEST-QUALITY가 weight 0인 이유는 quality가 이미 reliability/line coverage/branch coverage/test hygiene/coverage distribution을 합성해 기존 JAM 신호와 겹치기 때문이다. 이중 계상 대신 authoritative cap으로만 사용한다(Fenton & Pfleeger 1997; ISO/IEC 25023:2016; docs/03 §7.1).

v0.2 운영 데이터는 jam-full.json의 test details.quality에 보존된다. --test-baseline FILE/--test-fail-on-regression, 반복 --test-history FILE/--test-fail-on-flaky, --test-diff-base REF/--test-fail-diff-coverage PCT를 사용하면 comparison/history/changes가 채워진다. 이 데이터는 새 JAM 감점식을 만들지 않고 test-cli가 판정한 gate와 canonical score를 그대로 전달한다.

3.2 security 컴포넌트 하위 지표

security-clisecurity-report.json에서 summary, findings, insights, toolchain과 v0.2의 security_status, coverage, scanners, targets, baseline을 읽어 다음 하위 지표로 분해한다.

ID가중치목적산출식
SEC-SEVERITY0.25finding 심각도 부담을 점수화100 - critical×25 - high×12 - medium×5 - low×1 - unknown×2
SEC-POLICY0.18CI profile 정책 실패 반영100 - failed×20 - warnings×5
SEC-CATEGORY0.12secret/SCA/IaC 등 카테고리별 위험 반영category별 penalty 합산(secret 35, IaC/container 12, SAST 10, SCA/license 8, SBOM 5, 기타 4)
SEC-FIXABILITY0.10실패한 패키지 취약점의 수정 가능성 확인failing SCA/package finding 중 fixed_version 보유 비율
SEC-SUPPRESSION0.05suppression 남용 신호 반영100 - suppressed×10
SEC-TOOLCHAIN0.12스캐너/DB 상태가 신뢰 가능한지 확인toolchain DB ok/fresh/current=100, warn/old=70, stale/error/expired=40; DB age 24h 초과 70, 7d 초과 40
SEC-CVSS0.10취약점 정량 심각도 반영최대 CVSS 9 이상 20점, 7 이상 50점, 4 이상 75점; 미제공 시 not_assessed
SEC-CWE0.08CWE 위험군 반영CWE-79/89/798/918 등 고위험 CWE penalty 합산; 미제공 시 not_assessed
SEC-COVERAGE0.00“0 findings”가 실제 전체 scanner 수행 결과인지 검증complete+모든 requested scanner가 success/not_applicable이면 100; 그 외 measurement error

severity penalty는 기존 보안 점수의 baseline으로 유지된다. 다른 하위 지표가 baseline보다 낮으면 더 낮은 쪽을 사용한다. critical이 있으면 최대 50점, high가 있으면 최대 70점, policy failure가 있으면 최대 80점으로 제한한다. secret finding이 있으면 최대 40점, fixed version이 없는 high/critical SCA package가 있으면 최대 65/45점, scanner DB가 stale이면 최대 85/70점으로 제한한다. policy failure가 없고 critical/high도 없는 medium/low-only 리포트는 최소 70점으로 보정한다. 이는 "보안 주의사항 있음"과 "보안 게이트 실패"를 점수에서도 분리하기 위한 full 전용 보정이다.

SEC-COVERAGE는 severity score가 아니라 측정 타당성이므로 weight 0이다. schema 1에서 coverage.status != complete, requested=0, failed/skipped scanner, scanner 목록과 counter 불일치, security_status=blocked 또는 필드 누락이 있으면 security 컴포넌트는 status=error, reason=coverage_incomplete가 되고 exit 4를 유발한다. 낮은 security 점수로 합성하지 않는 이유는 “측정했더니 위험”과 “스캐너가 실행되지 않아 모름”을 구분하기 위해서다. ISO/IEC/IEEE 15939:2017의 measurement validity, NIST SP 800-218 SSDF v1.1 PW.7/PW.8, security-cli v0.2 계약이 근거다(docs/03 §7.1).

--security-baseline FILE --security-fail-on-new는 security-cli의 fingerprint 기반 new/persisted/resolved 비교와 gate를 활성화하며, 결과는 details.baseline에 보존된다.

3.2b lint 컴포넌트 (opt-in, v0.36+)

외부 코드 품질 린터(현재 ruff/Python; ESLint·golangci-lint·clippy는 후속)를 jam-full의 옵션 컴포넌트로 통합한다. --component lint(또는 all,lint)로만 활성화되며, 기본 jam full 동작·점수는 불변이다. jam-lite는 전혀 건드리지 않으므로 lite의 무조건 재현·오프라인 보증도 그대로다.

오프라인 전략: JAM은 PATH(또는 --lint-cli tool=path)의 로컬 린터 바이너리를 호출만 한다 (fetch/install 없음, 네트워크 0). 대상 언어에 린터가 없으면 not_assessed로 두고 그 가중치를 나머지 컴포넌트로 재정규화한다(0점 처리 아님).

재현성 전략 (조건부·자기기술적): lint는 jam-lite처럼 무조건 재현되진 않지만, "선언된 도구체인 하에서 결정적"이 되도록 만든다 — SEC-TOOLCHAIN과 같은 패턴.

  1. 설정 격리 + 룰 고정: 린터를 항상 프로젝트 설정 무시 모드로, JAM이 고정한 룰셋으로 실행한다

(ruff: check --isolated --select F,E9,B). 결과가 프로젝트의 임의 린터 설정이 아니라 (린터 버전 + JAM 룰셋 + 코드)에만 의존한다.

  1. JAM 파일 유니버스: 린터에 루트가 아니라 JAM이 발견한 파일 목록을 직접 넘긴다. 린터

자체의 .gitignore 기반 탐색(환경 편차 원인)을 배제하고 numerator/denominator 유니버스를 일치시킨다.

  1. 프로버넌스 각인: 컴포넌트 Details.tools[]린터 이름·정확한 버전·룰셋 ID·isolated 여부

기록한다. 두 lint 점수는 이 셋이 같을 때만 비교 가능하다.

  1. 미핀 시 신뢰 강등: 린터 버전을 못 읽으면(reproducible:false) 컴포넌트 점수에 상한(cap 90)을

걸고 요약에 표기한다.

스코어링: jam-lite와 동일한 SQALE 부채비율 모델(Letouzey 2012)을 쓴다 — score = 100·(1 − TDR/TDRMax), TDR = 교정부채 ÷ 개발비용(CLOC × 3.6분). 교정부채는 finding severity별 분(bug류 F/E9 = 10분, bugbear류 B = 3분), lintTDRMax = 0.10(lite와 동일). ad-hoc 밀도 기울기 대신 JAM 채점 철학에 얹어 노이즈 많은 프로젝트도 급락 없이 완만히 낮아진다. 테스트 파일 finding은 warning으로 하향(제품 위험 아님). PROVISIONAL: lint는 16종 lite 코퍼스에 없으므로 부채 분· TDRMax는 lint 코퍼스가 갖춰지면 보정한다.

어댑터 티어링(오프라인·빌드프리 적합성): ruff는 T1 정적(--isolated, 빌드·의존성 fetch 불필요 → 완전 오프라인·재현). golangci-lint·clippy는 T2 빌드필요(타입체크에 컴파일+의존성 fetch → 오프라인·빌드프리 위배), eslint는 프로젝트 node_modules 파서/플러그인 필요(조건부). T2는 검증 환경이 갖춰질 때 낮은 재현 등급으로 추가한다(미검증 어댑터는 배포하지 않음).

하위 지표: LINT-<TOOL>(툴별 SQALE 점수) + LINT-TOOLCHAIN(프로버넌스/신뢰). 가중치는 표시용이며 컴포넌트 점수는 전체 finding에 대한 SQALE로 직접 산출한다. 기본 컴포넌트 가중치 0.15 (활성 시에만 참여, full.weights.lint로 조정).

커버리지 비례 가중(coverage-scaled weight): lint는 어댑터가 있는 언어(현재 Python)만 커버하므로, 전체 종합에 미치는 영향은 그 언어가 코드베이스에서 차지하는 CLOC 비중에 비례해야 한다. 그렇지 않으면 대형 Rust/C++ 프로젝트의 소수 Python 빌드 스크립트가 전체 등급을 0.15 가중치만큼 좌우한다. 그래서 실효 lint 가중치 = 0.15 × (린트 대상 언어 CLOC ÷ 전체 CLOC)이고, 남은 가중치는 측정된 다른 컴포넌트로 재정규화된다. 예: hyperfine(Python 6%)은 lint 가중치 0.02로 줄어 종합이 lite와 사실상 같고(92/A), pygoat(Python 20%)는 0.06, 순수 Python 라이브러리는 비중만큼 온전히 반영된다. 비중은 컴포넌트 Details.coverageShare에 기록한다.

3.2c spec 컴포넌트 (opt-in, 외부 요구사항 검증 합성)

jam은 코드가 요구사항대로 동작하는지(ISO/IEC 25010의 기능 적합성)를 측정하지 않는다(docs/10 §1). spec 컴포넌트는 이 공백을 jam 스스로 메우는 것이 아니라, 외부 spec-cli가 산출한 요구사항별 검증 결과를 jam-full 종합에 합성만 하는 opt-in 컴포넌트다. --component spec(또는 all,spec)으로만 활성화되며, 기본 jam full 동작·점수는 불변이다. 계약의 참조 구현은 jhl-labs/spec-cli — 요구사항 문서(REQ ID)의 테스트 참조를 추적하고 test-cli 결과와 결합해 판정하는 결정론적 도구다 (설치: jhl-labs/dist의 spec-cli-v* 릴리스).

계약: spec-cli run <root> --format json --output-dir <out>/spec을 실행해 spec-report.json(schema_version 1)을 읽는다 — 스키마는 docs/schemas/spec-report.schema.json 참조.

{
  "schema_version": 1,
  "tool": {"name": "spec-cli", "version": "0.1.0"},
  "requirements_total": 2,
  "requirements": [
    {"id": "R1", "status": "verified", "evidence": "test:auth_test.go#L12"},
    {"id": "R2", "status": "failed", "note": "레이트리밋 스펙 미구현"}
  ]
}

스코어링: score = round(100 × verified / requirements_total). failed/unverified requirement는 verified가 아니므로 분자에서 빠질 뿐 별도 감점식은 없다.

게이트: failed > 0이거나 spec-cli의 exit code가 1이면 컴포넌트는 status=failed (reason=quality_gate)로 표시된다 — 요구사항 검증 실패는 낮은 점수가 아니라 게이트 실패로 다룬다. 리포트를 읽을 수 없거나(report_missing/report_invalid) requirements_total <= 0이면 status=error로 표시되고 §3.2d에 따라 미측정 처리(가중치는 다른 컴포넌트로 재정규화, 게이트는 InfrastructureFailed()로 별도 유지)된다.

spec-cli v0.2는 spec-report.json을 마지막에 publish하면서 spec-trace.jsonspec-summary.json을 함께 원자적으로 생성한다. JAM은 두 companion 파일을 모두 읽어 zero-weight SPEC-TRACE-GATE를 추가한다.

필드/산출물JAM 사용
trace diagnostics, suppressed_diagnosticscode/severity/fingerprint와 suppression 수를 evidence로 보존
trace/summary relation_kinds, state, severity counts추적성 상태와 관계 종류를 details에 보존
summary gate.trace_fail_on, trace_diagnostics, passedupstream이 실제 적용한 binary gate를 단일 원장으로 사용
summary report totalsspec-report.json과 requirements total 일치 검증

SPEC-TRACE-GATE는 passed=true면 100/ok, false면 0/failed지만 weight 0이다. 기능 점수는 계속 verified share이고, trace warning/error에 JAM 고유 penalty를 만들지 않는다. 요구사항 추적성의 근거는 ISO/IEC/IEEE 29148:2018이고, 구체 임계는 --spec-trace-fail-on none|info|warning|error로 spec-cli가 결정한다. companion 두 파일 중 하나만 존재하거나 report/trace/summary total이 다르면 report_invalid 측정 오류다.

--spec-requirements PATH, --spec-trace-baseline FILE, --spec-trace-fail-on LEVEL은 각각 v0.2의 요구사항 문서, suppression baseline, trace gate에 전달된다. jam-full.json.artifactsspecReport, specTrace, specSummary 경로를 모두 기록한다.

명명: 컴포넌트 이름은 "Functional (external)"로 고정한다. jam이 기능 적합성을 직접 측정한 것으로 오인되지 않도록, 리포트 어디에도 "Functional"이 jam 자체 지표인 것처럼 표기하지 않는다.

프로버넌스: Detailstool(name/version), requirementsTotal, verified, failed, unverified, trace/summary를 기록해 어떤 spec-cli 버전이 몇 건 중 몇 건을 검증했고 어떤 trace gate를 적용했는지 리포트에서 바로 확인할 수 있게 한다.

기본 가중치: 0.15 (lint와 동일 수준의 opt-in 보수적 가중치, full.weights.spec으로 조정 가능). all에는 포함되지 않는다.

3.2d 미측정 컴포넌트 처리 ("측정 못 함" ≠ "측정해서 나쁨")

종합 숫자는 측정된 품질만 반영한다. 요청한 컴포넌트가 측정되지 못한 경우 — 도구 부재, 리포트 판독 실패, 타임아웃(error), 또는 해당 언어에 적용 불가(not_assessed) — 그 컴포넌트는 가중 합에서 제외되고 가중치가 측정된 컴포넌트로 재정규화된다. 0점으로 종합을 끌어내리지 않는다. 이는 "측정 못 함"과 "측정해서 나쁨"을 분리하기 위함이다: security-cli가 설치돼 있지 않다고 해서 보안 점수가 낮은 것처럼 읽혀서는 안 된다.

단, 게이트와 점수 사용 가능성은 별개로 유지된다. error/not_assessed 컴포넌트 또는 불완전한 jam-lite 무결성이 있으면 decision=incomplete, score.status=provisional, score.usable=false다. jam full은 비영(exit 4)으로 종료하고, 리포트·CLI 요약에 NOT DECISION-GRADE와 원인을 크게 표기한다. 즉 표시 숫자는 일부 성공한 측정의 진단값일 뿐이며 순위·릴리스 판정에 사용할 수 없고, 스캐너가 사라져도 CI가 조용히 통과하지 못한다. 컴포넌트가 실행돼 품질 게이트만 실패한 경우(failed, 예: 테스트 실패지만 커버리지는 측정됨)는 실제 측정이므로 종합에 그대로 포함된다.

예: JAM 자기 스캔(--component all,lint)에서 test-cli는 실행(87/B), security-cli는 부재(error), lint는 Go 프로젝트라 not_assessed. 측정된 lite(90)+test(87)만으로 잠정 89/B가 산출되지만 usable=false, decision=incomplete이며 security/lint 미측정 원인과 함께 exit 4가 된다.

3.3 리포트 표현

jam-full.json schema v2는 score.status=final|provisional, score.usable, decision.status=pass|fail|incomplete, decision.reasons를 포함한다. 각 컴포넌트는 metrics 배열을 포함할 수 있고 jam-full-report.md도 같은 하위 지표를 표로 렌더링한다. 외부 도구의 원본 evidence는 계속 test/report.json, security/security-report.json, spec/spec-*.json에 보존되며, jam-full의 metrics는 합성 점수 산출을 위한 해석 레이어다. lint 컴포넌트는 Details.tools[]에 도구체인 프로버넌스(린터 버전·룰셋·isolated)를 기록한다.

3.4 설정 override

jam.yamlfull 섹션으로 컴포넌트 가중치와 하위 지표 weight/floor/cap을 조정할 수 있다. CLI 플래그로 선택한 component set은 그대로 우선하며, 선택된 컴포넌트 가중치 합은 1.0으로 재정규화한다.

TEST-QUALITY, SEC-COVERAGE, SPEC-TRACE-GATE는 producer 계약의 canonical score/validity/gate이므로 override 대상이 아니다. 세 signal의 weight 0과 score/status는 고정되어 fleet 정책이 측정 타당성을 우회하거나 동일 evidence를 이중 가중하지 못한다.

full:
  weights:
    jam-lite: 0.45
    test: 0.30
    security: 0.25
  metrics:
    TEST-DENSITY:
      weight: 0.18
      cap: 80
    TEST-SOURCE-COV:
      weight: 0.12
      cap: 90
    SEC-TOOLCHAIN:
      weight: 0.20
    SEC-CVSS:
      floor: 20

4. 종료 코드

code의미
0측정 성공, 품질 게이트 통과
1--fail-under, test, security 중 하나의 품질 게이트 실패
2jam 자체 입력/설정/리포트 작성 실패
3--strict에서 jam-lite 파스 실패
4jam-full 측정 불완전(decision=incomplete; jam-lite 무결성 또는 외부 컴포넌트 증적 부족)

full 모드에서 --fail-under는 jam-full 총점에 적용한다. lite 모드에서는 jam-lite 점수에 적용한다.

jam-full.json의 컴포넌트에는 실패 분류용 reason이 들어갈 수 있다. 주요 값은 no_test_evidence, tool_unavailable, report_missing, report_invalid, coverage_incomplete, timeout, remote_rate_limit, quality_gate, security_policy다. status=failed는 완전하게 측정된 품질 게이트 실패이므로 decision=fail과 최종 점수를 만든다. status=error|not_assessed는 측정 인프라/타당성 실패이므로 decision=incomplete와 잠정 점수를 만든다.

5. 경계

test와 security는 별도 CLI의 책임으로 둔다. jam-lite는 test/security가 아닌 정적 소프트웨어 품질 지표를 계속 확장한다.

jam-lite에 남은 주요 확장 후보: