JAM Metrics Spec 변경 이력
규칙: 11-metrics-versioning.md. 레지스트리 (internal/metrics/) 를 바꾸는 모든 PR 은 이 파일을 함께 갱신해야 한다.
v14.5.0 (2026-07-31)
MINOR — docs/18 P4 완결. 5개 지표 전부 info 캘리브레이션(감점 0) 또는 opt-in이라 16종 lite 코퍼스 점수·등급 불변.
- HYG-16 중복 설명 주석 (신규, info): 다음 코드 라인을 그대로 읽어주는 주석(토큰 중첩 ≥70%)이 파일당 ≥5건이면 요약 보고. SATD·주석 처리 코드·pragma 제외. 근거: Coleman et al. (1994); GitClear (2025)의 주석 인플레이션 관측.
- HYG-17 미해석 내부 import (신규, info): 상대 경로 import(JS/TS
./·../, Python 점 상대)가 발견된 파일로 해석되지 않으면 보고. bare specifier·alias·tsconfig paths는 대상 밖 — alias 미구현(roadmap M2-4)으로 인한 오탐이 구조적으로 배제된다. 근거: CWE-1078 계열; 동적 로딩 언어의 런타임 잠복 결함. - SIZE-05 사변적 일반화 (신규, opt-in, info):
jam.yaml에profile: application명시 시에만, 프로젝트 내부 미참조 exported 심볼(Go)을 보고(상위 20건,Deprecated:제외). 라이브러리 공개 API 오탐을 프로파일 게이트로 차단. 근거: Fowler (1999, *Refactoring*)의 Speculative Generality. - CHURN-03 테스트 동반 변경율 (신규, opt-in, info): 프로덕션 커밋 중 테스트 동반 변경 비율(프로덕션 커밋 ≥10건, 테스트 있는 저장소 한정). 근거: Zaidman et al. (2011, EMSE).
- CHURN-04 거대 일괄 커밋 (신규, opt-in, info): 추가 라인이 평균+2σ 초과·절대 하한 1,000줄 이상인 커밋 상위 3건. 근거: Purushothaman & Perry (2005, IEEE TSE); Nagappan & Ball (2005).
- 신규 설정: 최상위
profile: library|application키(미설정 시 SIZE-05 무발화).
v14.4.0 (2026-07-31)
MINOR — docs/18의 P2 구현. CPLX-06의 opt-in churn 인프라(churn.enabled + git 저장소, 미설정 시 무발화)를 공유하며 모두 info·점수 중립이라 16종 lite 코퍼스 점수·등급 불변(코퍼스는 churn 미설정).
- CHURN-01 단명 코드율 (신규, opt-in, info): 최근 12개월 커밋에서 추가 후 14일 내 같은 파일이 재수정된 라인 비율(커밋 단위 근사). 최근 14일 추가분은 판정 불가라 분모 제외. 프로젝트 요약(적격 ≥500줄) + 재작업 집중 파일(적격 ≥100줄·비율 ≥30%, 상위 5개). 근거: GitClear (2024/2025, *AI Copilot Code Quality*)의 2주 내 재수정 상승 실증; Tornhill (2015).
- CHURN-02 AI 귀속 커밋 비율 (신규, opt-in, info):
Co-Authored-By/"Generated with" trailer 매칭 커밋 비율. 품질 판단이 아닌 코호트 분해용 분모 신호. 근거: Forsgren et al. (2021, SPACE, ACM Queue). 거부 결정: 코드 내용 기반 AI 생성 확률 추정은 오탐 해악·근거 표준 부재로 채택하지 않음(docs/18 §6). - 두 지표는 CPLX 카테고리로 등록한다(CPLX-06과 churn 인프라·게이트 공유; 신규 카테고리 신설은 가중치 근거가 필요한 MAJOR 사안).
v14.3.0 (2026-07-31)
MINOR — docs/18 AX·AI 생산성 설계의 P1 구현. 모두 점수 중립이라 16종 lite 코퍼스 점수·등급 불변.
- HYG-15 잔여 플레이스홀더 (신규, info 캘리브레이션): production 코드의 생성 템플릿 흔적(
your_api_key류 자격증명 자리표시자,changeme/replace_me,lorem ipsum, "as an AI language model")을 보수적 토큰 목록으로 보고한다. 테스트·example/template/docs 경로는 자리표시자가 의도이므로 제외. 근거: Potdar & Shihab (2014, *An Exploratory Study on Self-Admitted Technical Debt*, MSR)의 SATD 개념의 생성 시대 변형; SEC-01과 상보. - HYG-18 동어반복 테스트 (신규, info): 테스트 파일의 항상 참 단언(
assert(true),assert True,assertTrue(true),expect(true).toBe(true),require.True(t, true))과 동일 인자 동등 단언(assertEqual(x, x), testifyEqual(t, x, x))을 보고한다. 테스트 역할은 점수 모집단 밖. 근거: van Deursen et al. (2001, *Refactoring Test Code*, XP2001)의 테스트 냄새 분류. - HYG-16(중복 설명 주석)·HYG-17(미해석 내부 import)은 docs/18 §5의 선행 과제(다국어 불용어, tsconfig paths 해석) 해소 후 도입하며 ID만 예약 유지.
v14.2.0 (2026-07-31)
MINOR — 커버리지 격차 4종을 전부 점수 중립 캘리브레이션으로 보강했다. 신규/확장 신호는 모두 info 등급(부채 0)이거나 점수 모집단 밖이며, 16종 lite 코퍼스 점수·등급 전부 불변이다. 가중치 있는 정식 승격(예: DEP 카테고리 신설)은 캘리브레이션 데이터 축적 후 별도 MAJOR로 다룬다.
- HYG-07 v2 — 파스 실패 다언어 확장: tree-sitter 언어(TS·Java·Python·C#·C++·Rust)에서 명백히 깨진 파스 트리(루트 ERROR 등 보수 판정)를 info·confidence low로 보고한다. 기존 Go 판정(위반 + 등급 최대 C 제한)은 불변이며, 등급 상한은 violation 등급 HYG-07에만 발동하도록 명시했다 — 비-Go 파스 오류가 조용히 지표 누락으로 이어지던 측정 타당성 구멍을 가시화한다. 근거: ISO/IEC 25010 및 ISO/IEC/IEEE 15939:2017의 측정 타당성·완전성 요구.
- SEC-07/08 v2 — Python·Java 휴리스틱 확장 (info 캘리브레이션): 경로 싱크(open/Paths.get/File 스트림 등)와 HTTP 클라이언트(requests/urllib/httpx, URL/HttpClient)에 동적 구성 인자가 전달되는 패턴을 info·confidence low로 보고한다. TS/JS 기존 동작·점수는 불변. OWASP BenchmarkJava 라벨 벤치마크로 정밀도가 검증되기 전까지 감점하지 않는다. 근거: MITRE CWE-22, CWE-918; 기존 SEC-07/08 근거와 동일한 싱크·소스 분류.
- HYG-14 의존성 고정 위생 (신규, info): 매니페스트 대비 lockfile 부재(package.json↔lockfile, poetry↔poetry.lock, Pipfile↔Pipfile.lock, go.mod↔go.sum, 루트 Cargo.toml↔Cargo.lock)와 package.json의 유동 버전(
*·latest·상한 없는 범위;^/~는 표준 관행이라 제외)을 보고한다. 매니페스트는 configuration 역할이라 v13 모집단 규칙상 항상 점수 밖인 순수 보고 신호다. 근거: NIST SP 800-218 SSDF v1.1 PO.1(의존성 명세·무결성), 재현 가능 빌드 관행(SLSA); 유동 범위 제외는 npm semver 표준 관행. - CPLX-06 변경 핫스팟 (신규, opt-in, info):
jam.yaml의churn.enabled: true일 때만 git 이력(최근 12개월git log --numstat)의 파일별 변경 횟수 × 복잡도 상위 파일을 info로 보고한다. 미설정/비-git 트리에서는 완전 무발화(ARCH-09 전례). 이력은 환경 의존적이므로 점수에 산입하지 않는 리팩터링 우선순위 신호다. 근거: Nagappan & Ball (2005, *Use of Relative Code Churn Measures to Predict System Defect Density*, ICSE); Tornhill (2015, *Your Code as a Crime Scene*)의 hotspot 방법론.
v14.1.0 (2026-07-31)
MINOR — 신규 지표 2종(모두 점수 중립)과 판정 견고성 수리. 16종 lite 코퍼스 점수·등급 전부 불변: RES-04는 info 등급 캘리브레이션(감점 0), HYG-13은 테스트 파일 전용이라 v13 production 모집단 규칙상 항상 점수 밖이다.
- RES-04 네트워크 타임아웃 부재 (신규, Go, info 캘리브레이션): 기본 공유 클라이언트를 쓰는
http.Get/Post/PostForm/Head호출과Timeout필드 없는http.Client리터럴을 보고한다. 컨텍스트 데드라인 가능성 때문에 confidence low. CPLX-04 전례대로 코퍼스 정밀도 검증 전까지 감점 없는 info로 도입한다. 근거: MITRE CWE-1088(Synchronous Access of Remote Resource without Timeout), CWE-400; Nygard (2007, *Release It!*)의 timeout 안정성 패턴. - HYG-13 단언 없는 테스트 (신규, Go
_test.go, info):t.*호출·assert./require.호출·t위임이 전혀 없는Test*함수를 보고한다. 테스트 역할 파일은 점수 모집단 밖이므로 순수 보고 신호다. 근거: van Deursen, Moonen, van den Bergh & Kok (2001, *Refactoring Test Code*, XP2001); Bavota et al. (2012, *An empirical analysis of the distribution of unit test smells*, ICSM). - SIZE-04 god-type 판정 견고화 (점수 불변): §2.9 상한이 메시지의 리터럴
"God Type"부분 문자열에 의존하던 것을metrics.GodTypeMarker상수로 중앙화했다. 메시지 문안 변경/현지화가 상한을 조용히 무력화하는 위험 제거. 출력 메시지는 동일하다. - 문서 정정: docs/03 §2.2의 SIZE-01 비용 설명을 구현(심각도 기본 비용)과 일치시켰고, score 엔진의 HighRiskShare 주석을 docs/03 §2.7의 실제 분모(카테고리 eligible production 파일 수)와 일치시켰다. 산식 변경 없음.
v14.0.0 (2026-07-14)
MAJOR — jam-full의 test-cli/security-cli/spec-cli v0.2 계약을 계측 계약으로 승격했다. jam-lite 산식과 16종 lite 코퍼스 기준선은 변하지 않지만, report@2를 쓰는 full 테스트 점수와 불완전 보안 스캔의 판정이 달라지므로 v13 full 기준선과 직접 비교하지 않는다.
TEST-QUALITY(weight 0, authoritative cap):test-cli/report@2의 canonicalquality.score/grade/risk/dimensions/findings/static/slowTests/coverageHotspots/comparison/history/changes를 보존한다. 기존 9개 JAM 테스트 하위 지표는 유지하되 최종 test 점수는min(JAM 기존 합성, test-cli quality.score)다. 같은 pass/coverage 사실을 새 양의 가중치로 다시 더하지 않기 위해 weight는 정확히 0이며, report@1에서는not_assessed다. 공개 v0.2.0 실측에서 기존 JAM 87점과 upstream 76점의 불일치를 76점으로 정정했다. 근거: Fenton & Pfleeger (1997), *Software Metrics: A Rigorous and Practical Approach*, 2nd ed.의 합성 척도·평균 은폐 경고; ISO/IEC 25023:2016의 정의된 품질 측정치와 해석 경계; test-cli v0.2test-cli/report@2계약. 거부 결정: upstream 5개 dimension을 JAM 가중치에 재투입하는 안은 동일 evidence의 이중 계상이라 채택하지 않았다.SEC-COVERAGE(weight 0, fail-closed validity gate): security-cli schema 1의security_status,coverage,scanners,targets,baseline을 읽는다.coverage.status=complete,requested>0, 모든 요청 스캐너가success|not_applicable, 요약 카운터와 scanner evidence가 일치할 때만 100/valid다.blocked, failed/skipped/missing/inconsistent coverage는 보안 저점이 아니라 미측정status=error, reason=coverage_incomplete, exit 4로 처리한다. finding 0건을 scanner 미실행과 구별할 수 없기 때문이다. v0.1 legacy report는 읽되 이 지표가not_assessed임을 명시한다. weight 0은 finding 심각도 점수를 중복 감점하지 않고 측정 타당성만 게이트하기 위한 값이다. 근거: ISO/IEC/IEEE 15939:2017의 측정 결과 타당성·측정 과정 증적; NIST SP 800-218 SSDF v1.1 PW.7/PW.8의 코드 검토·분석·테스트 수행 및 결과 기록; security-cli v0.2의 명시적 scanner coverage 계약. 거부 결정:succeeded/requested를 양의 가중 점수로 평균내는 안은 실패 스캐너가 clean finding 점수에 희석될 수 있어 채택하지 않았다.SPEC-TRACE-GATE(weight 0, upstream binary gate): spec-cli v0.2의 원자적spec-trace.json/spec-summary.json을 읽고 diagnostic·suppression·relation kind·state와 실제trace_fail_on게이트를 보존한다. 게이트 통과=100, 실패=0의 감사 신호지만 weight 0이라 기존verified/requirements_total기능 점수를 중복 변경하지 않는다. 두 companion 파일이 한쪽만 있거나 requirements total이 서로 다르면 계약 불완전으로status=error다. 근거: ISO/IEC/IEEE 29148:2018의 요구사항 추적성 및 검증·확인 정보 항목; ISO/IEC/IEEE 15939:2017의 일관된 측정 산출물; spec-cli v0.2 trace/summary 계약. 거부 결정: warning/error 건수에 임의 감점 계수를 붙이지 않고, 운영자가 spec-cli의 표준trace_fail_on을 선택하도록 했다.- 운영 데이터 전달:
--test-baseline, 반복--test-history,--test-diff-base와 대응 fail gate,--security-baseline/--security-fail-on-new,--spec-requirements/--spec-trace-baseline/--spec-trace-fail-on을 companion CLI에 전달한다. 비교·history·changed-line·new-finding 데이터는 원본과jam-full.jsondetails에 보존된다. 이 전달 자체는 새 임계나 가중치를 만들지 않는다. - 계약 엄격화: test는
report@1|@2만, security는 legacy schema 0 또는 schema 1만, spec report/trace/summary는 schema 1과tool.name=spec-cli만 수락한다. 알려지지 않은 미래 스키마를 조용히 오해하지 않는다. 세 zero-weight 계약 signal은full.metricsoverride 대상에서도 제외해 중앙 설정이 producer의 canonical score나 측정 타당성 gate를 우회하지 못한다.
v13.0.0 (2026-07-14)
MAJOR — 점수의 측정 모집단과 분모를 명시적으로 정규화했다. 동일 소스를 다시 측정해도 v12 계열과 점수를 직접 비교할 수 없으며, v13 기준선을 새로 만들어야 한다.
- 파일 역할 분리: 분석 입력을
production/test/documentation/configuration/generated로 분류한다. 모든 finding은 감사 산출물에 보존하지만 production이 아닌 finding은debt_counted=0과score_exclusion=<role>로 명시한다. SonarQube도 main/test 소스를 별도 범위로 두고 test 파일을 source 관련 지표와 LOC에서 제외한다. 근거: SonarSource, *Setting the initial scope*; ISO/IEC/IEEE 15939:2017의 명시적 측정 범위·정보 요구·측정 타당성 관리. - 카테고리×언어 eligible 분모: 각 카테고리의
dev cost = eligible production CLOC × 3.6분.eligible은 해당 카테고리의 구현된 rule set이 지원하는 언어만 뜻한다.coverage = eligible production CLOC / all production CLOC를 카테고리마다 보고한다. 지원하지 않는 언어를 분모에 넣어 점수를 올리거나, test/docs/config를 추가해 debt를 희석하는 경로를 제거했다. 근거: El Emam, Benlarbi, Goel & Rai (2001), *The Confounding Effect of Class Size on the Validity of Object-Oriented Metrics*, IEEE TSE 27(7); Letouzey (2012), *The SQALE Method for Evaluating Technical Debt*, MTD@ICSE, DOI 10.1109/MTD.2012.6225997; SonarSource의 언어별 Quality Profile 모델. - 측정 불가를 점수와 분리: eligible production CLOC가 0인 카테고리는 가중 합에서 제외하고 가중치를 재정규화한다. 모든 카테고리가 측정 불가면
score.status=not_assessed,grade=N/A이며 0/F로 가장하지 않는다.jam-result.json은 v3,jam-run.json은jam/run-manifest@2로 올려 production scope·role CLOC·category coverage를 기계 판독 가능하게 기록한다. - 단일 파일 30% debt 할인 제거: remediation cost는 finding별 비용의 가산 합으로 계산한다. 기존 “한 파일이 카테고리 debt의 30%까지만 기여” 규칙은 출처가 없고, 합계 자체를 기준으로 다시 cap하는 순환 정의라 재현 가능한 표준 규칙이 아니었다. SQALE은 요구사항 위반별 remediation cost를 더해 debt를 구성하므로, 결함이 한 파일에 모였다는 이유만으로 수정 비용을 할인하지 않는다. 동일 신호의 중복 완화는 메트릭 정의·비용에서 처리하며 원시 debt를 사후 절사하지 않는다. 거부 결정을 기록: 집중 결함의 평균 은폐 문제는 할인으로 해결하지 않고 risk profile/근거 있는 worst-case 상한(§2.6~2.10)으로 다룬다. 근거: Letouzey 2012; Heitlager, Kuipers & Visser (2007), QUATIC; Baggen et al. (2012), *Standardized code quality benchmarking*, Software Quality Journal 20(2), DOI 10.1007/s11219-011-9144-9.
- 회귀 계약: 문서·테스트·설정·생성 파일 추가는 production 점수를 바꾸지 않고, 미지원 언어는 지원 카테고리의 분모를 키우지 않으며, score-excluded finding은 SEC/집중/등급 cap과
diff --fail-on-added를 발동하지 않는다. 고정 16종 코퍼스는testdata/e2e-corpus.yaml의 v13 기준선으로 재측정한다. - 코퍼스 실측: jam v0.38.0으로 고정 SHA 16종을 전수 재스캔해
testdata/e2e-corpus.yaml을 exact score로 재핀했다. v12 대비 production-only 분모와 가산 debt 때문에 14종이 하락, 2종은 불변이며, test finding은fmt193건·stateless33건·ts-is7건처럼 감사 출력에 남고 점수에서는 제외된다. 결과는docs/13-e2e-sample-evaluation.md에 production CLOC·coverage·완전성과 함께 기록했다. docs/config/test에서만 발생한 skip/parse 실패는 production 측정 완전성을 훼손하지 않도록 integrity 판정도 동일 모집단으로 정렬했다.
v12.3.0 (2026-07-11)
- ARCH-09 레이어 규칙 위반 추가: jam.yaml
arch.layers/arch.rules(deny)로 선언된
레이어 정책을 import 그래프 edge에 검사. 위반 edge당 45분, confidence high. 규칙 미선언 시 미측정(기존 프로젝트 점수 불변). (docs/02 ARCH-09, docs/07 §3)
- jam-full spec 컴포넌트(opt-in,
--component spec): 외부 spec-cli 계약
리포트(요구사항별 verified/failed/unverified)를 합성. failed는 quality gate. jam이 기능 적합성을 측정하는 것이 아니라 외부 결과를 합산함을 리포트에 "Functional (external)"로 명시. (docs/10 §1, docs/12 §3.2c)
v12.2.0 (2026-07-03)
MINOR — HYG-12 정적 검사기 억제(blanket static-check suppression) 1종 추가. 새 메트릭만 추가하고 산식/임계/가중치/캡은 불변이라 기존 지표 점수 불변. 외부 도구 없이 자체 구현한 라인 스캔이며 다언어 공통. 코퍼스 16종 점수 전부 불변(무범위 억제가 코퍼스에 0건이라 완전 dormant).
- 문제(미커버 축): 에이전트가 타입 오류를 못 고칠 때 가장 빠른 "green 만들기"는 검사기를 통째로 끄는 것 —
@ts-ignore, 무코드# type: ignore,#pragma warning disable,@SuppressWarnings("all"). 실제 결함을 숨기는 바이브코딩의 대표 tell인데 어떤 지표도 측정하지 않았다(HYG-03은 TODO류 주석만 봄). docs/05 §2.4의 언어별 보강 룰도 문서에만 있고 미구현이었다. - 규칙: 무범위(uncoded) 억제만 warning으로 잡는다 —
@ts-ignore/@ts-nocheck, 무코드# type: ignore/# mypy: ignore-errors, 무코드#pragma warning disable/#nullable disable,@SuppressWarnings("all"). 정밀도 게이트: 규율 있는 범위 지정 형태는 제외한다 —@ts-expect-error(오류 사라지면 자기 실패),# type: ignore[arg-type](검증된 코드),#pragma warning disable CS8600,@SuppressWarnings("unchecked"), Rust#[allow(...)](타입 오류를 끌 수 없는 lint 제어). Go/Rust/C/C++는 wholesale 타입 침묵 관용구가 없어 대상 아님. - 근거: SonarSource S1309(@SuppressWarnings 금지), typescript-eslint
ban-ts-comment(‘@ts-ignore대신@ts-expect-error’), mypywarn_unused_ignores; 억제는 SATD(Potdar & Shihab 2014)의 코드 레벨 형태. docs/02 §HYG-12, 참고문헌 32. - 캘리브레이션: 무범위 억제가 16종 코퍼스에 0건(itsdangerous의
# type: ignore6건은 모두[code]형태, sindresorhus/is의 52건은 라인 범위eslint-disable) → 완전 dormant, 코퍼스 점수 전부 불변(로컬 클론 12종 재스캔으로 확인 — 전원 anchor 유지). best 프로젝트 오탐 0. - 테스트:
TestHYG12BlanketSuppression(발화 + 규율 형태 제외 게이트). 레지스트리 1건 추가(Since 12.2.0), 분석기internal/analyze/hyg/hyg12.go.
v12.1.0 (2026-07-03)
MINOR — 바이브코딩 위생 지표 4종 추가(HYG-08~11). 새 메트릭만 추가하고 산식/임계/가중치/캡은 바꾸지 않으므로 기존 지표 점수는 불변; 카테고리/종합 점수는 새 HYG finding이 얹히는 곳에서만 변할 수 있다. 모두 외부 도구/라이브러리 없이 자체 구현한 라인/토큰 스캔이며 빌드 없이 여러 언어에 공통 적용된다. 코퍼스 16종 점수 전부 불변(검증: best/stress 12종 로컬 클론 직접 스캔 — go-cleanhttp 100/A, ts-is 97/A, itsdangerous 98/A, hyperfine 92/A, stateless 92/A, gs-rest 100/A, fmt 95/A, linenoise 84/B, how2heap 94/A, rustlings 87/B, pygoat 79/C, nodegoat 79/C — 각 anchor와 정확히 일치; 나머지 4종은 SEC critical로 C 고정이라 HYG가 등급을 바꿀 수 없음).
- HYG-08 주석 처리된 코드(SonarSource S125): 코드로 보이는 연속 전체 라인 주석 런(코드 유사 ≥3줄, 비율 ≥0.6). HYG-02(미참조 심볼)를 보완해 "파서가 못 보는 죽은 코드"를 잡는다. 문서 주석(
///·shebang)·SATD·마크다운/doc 태그·선언 직전 doc 주석(godoc 관례)은 게이트로 제외. 다언어 공통, warning/medium. 실검출 예: fmtsupport/docopt.py, pygoatviews.py, nodegoatsession.js. - HYG-09 미구현 스텁(SonarSource S3717): 코드 레벨 미구현 마커 — Rust
todo!()/unimplemented!(), C#NotImplementedException, Gopanic/errors+ "not implemented" 문구, JS/TSthrow new Error(…not implemented…), JavaUnsupportedOperationException(…). HYG-03(주석 SATD)의 코드 레벨 짝. 정밀도 게이트: Pythonraise NotImplementedError()무인자형은 비공식 추상 메서드 관용구라 제외하고 문구를 담은 형태만 잡는다(itsdangeroussigner.py의 베이스 메서드 FP를 이 게이트가 차단) —@abstractmethod문맥도 제외. 실검출 예: rustlings 연습문제todo!()14건(87/B 유지). - HYG-10 디버그 출력 잔재(CWE-489): 디버그 전용 마커만 —
dbg!·console.debug/trace/dir·.printStackTrace()·breakpoint()/pdb.set_trace()·Debugger.Break(). 일반 콘솔 출력(console.log·print·fmt.Print*·println!·System.out.*)은 의도적으로 제외 — 이중 용도라(CLI stdout이 곧 산출물; hyperfine이 라이브러리 모듈에서println!로 결과 출력) flag하면 깨끗한 CLI 프로젝트에 오탐(초안에서 hyperfine 92/A에 오탐이 나 weak 티어를 제거함). Go/C/C++은 디버그 전용 표준 호출이 없어 대상 아님. warning/medium. - HYG-11 명명 규칙 비일관성(Deissenboeck & Pizka 2006, *Concise and consistent naming*, SQJ): 언어별 비테스트 함수 이름 snake_case vs camelCase 혼용 — 표본 ≥20, 소수 스타일 ≥25%면 언어당 1건. 세션 간 스타일 표류(에이전트 코딩 증상)를 잡는다. Go 제외(exported/unexported 대문자 관례가 규칙), C/C++ 제외. benchmark-derived 임계(깨끗한 단일 스타일 프로젝트 소수 비중 ~0%). warning/medium.
- 근거: docs/02 §HYG-08~11 및 참고문헌 28~31. 테스트:
TestHYG08CommentedOutCode/TestHYG09UnimplementedStub/TestHYG10DebugOutput/TestHYG11NamingConsistency(발화 + 오탐 방지 게이트). 레지스트리 4건 추가(Since 12.1.0, Version 1), 분석기internal/analyze/hyg/hyg08~11.go.
v12.0.0 (2026-06-15)
MAJOR — CPLX 극단 복잡도 상한(docs/03 §2.10) 신규 점수 규칙. SEC(§2.6)·ARCH(§2.8)·SIZE(§2.9)에 이은 4번째 카테고리 ceiling. 코퍼스 16종 점수 불변; god component를 가진 실 프로젝트만 정정.
- 문제(과한 점수): findings 리뷰에서 CPLX가 density로 희석되는 마지막 누적 차원임이 드러남. gitops-console(4709줄 React 컴포넌트, CCN 445)이 CPLX 94, sepilotd(CCN 1046, CCN≥100 함수 28개)가 CPLX 95 — 병적 god function이 크기 분모에 가려짐.
- 규칙: CCN≥100 함수 개수로 CPLX 카테고리에 상한(1개→89, ≥2개→79). 근거: McCabe(1976) — CCN>10 위험, >50 테스트 불가, ≥100은 어떤 기준으로도 god function(정당한 단일 함수는 도달 불가).
- 캘리브레이션: 16종 코퍼스 전부 CCN≥100 함수 0개(최대 fmt CCN 77) → 코퍼스 점수 전부 불변. god component 가진 실 프로젝트만: gitops 91/A→88/B, sepilotd 80/B→77/C, jpad-web 84/B→80/B; jam(max CCN 51) 불변.
- 테스트:
TestCplxExtremeCeiling,TestCplxBelowExtremeNoCeiling(CCN 77 보호).
v11.1.0 (2026-06-15)
MINOR — findings 리뷰 후속 2건. 코퍼스 16종 점수 불변.
- Inter-procedural taint(한 단계): SEC-07/08 taint가 같은 파일 헬퍼 한 단계를 따라간다 — source-반환 게터(
function getId(req){ return req.query.id })나 값-passthrough(파라미터가 호출 없이 반환에 도달; 새니타이저는 호출이라 체인 유지). recall↑, 코퍼스엔 그런 흐름이 없어 무발화. 테스트:TestTaint_InterProc_SourceReturningHelper/_Passthrough/_SanitizingHelperBreaksChain(새니타이저 zero-FP 보존). - 벤더 라이브러리 제외:
/*!라이선스 배너(배포 라이브러리 관례)로 식별되는 in-tree JS/TS(예: 비압축 bootstrap.js)를 generated로 제외. minified-라인 휴리스틱 보완. govwa bootstrap.js findings 제거(79/C 유지). - C# injection은 갭 아님(검증): ADO.NET concat·
Process.Start·EFFromSql(Raw)주입을 모두 critical로 검출(dvcsharp 실주입 포함). 투기적 sink 추가 안 함.
v11.0.0 (2026-06-14)
MAJOR — findings 리뷰에서 발견한 과탐(FP)/누락(FN)을 수정. best 프로젝트 2개의 등급이 FP 제거로 정정됨(ts-is B→A, itsdangerous 90→98/A). stress 앱은 실코드 취약점이 그대로 cap.
- 과탐 #1 — 테스트 코드 SEC: test/spec/fixture/mock 파일의 SEC finding을 warning/low로 강등(제거 아님 — 가시성 유지, docs/03 §4). 테스트의
new Function/eval/약한 암호는 제품 공격면이 아니므로 worst-case 상한을 발동시키면 안 됨. ts-is: 테스트 전용new Function이 SEC를 60으로 cap하던 FP 제거 → 89/B→97/A. (sec.godowngradeTestFindings, 기존 SEC-03 test-path 강등 패턴을 전 SEC로 일반화.) - 과탐 #2 — SEC-03 HMAC-SHA1: 파일이
hmac모듈을 쓰면 SHA-1을 약한 해시로 보지 않음(HMAC-SHA1은 키 기반이라 안전; CWE-327은 평문 해시 대상). itsdangerous의 HMACAlgorithm digest FP 제거 → 90→98/A. MD5는 계속 flag. - 누락 #1 — NoSQL 인젝션(CWE-943): SEC-02에 MongoDB
$where/$function/$accumulator+ 동적 문자열(템플릿/concat) 검출 추가. NodeGoat{$where: \…${userInput}…\}류를 잡음(SQL 키워드 룰이 놓치던 것). JS/TS, critical. - 과탐 #3 — RES-01 테스트 노이즈: RES-01(자원 누수)이 테스트 파일을 건너뜀. cpp-fmt의 gtest/test
new누수 FP 제거. - 과탐 #4 — DUP 프로젝트율 요약: 프로젝트 중복률 roll-up finding(epsilon debt)을 warning으로 상한. "56% critical"이 높은 DUP 점수 옆에 뜨던 모순 제거(실제 debt는 per-block finding이 담당). 관용적 fluent/type-guard 반복을 critical로 과장하지 않음.
- 검증: best 회귀 0(go-cleanhttp 100, gs-rest 100, cs-stateless 92, hyperfine 92, cpp-fmt 95, c-linenoise 84 불변); ts-is·itsdangerous만 FP 제거로 상승. stress 6종 79/C(SEC=25) 유지(실코드 취약점이 cap). sepilotd 80/B 불변. 테스트:
TestSEC02_NoSQLInjection,TestSEC03_Sha1HmacGate,TestSEC_TestPathDowngrade.
v10.1.0 (2026-06-14)
MINOR — 언어 커버리지 audit에서 발견한 분석 누락/과탐 2건을 discover 단계에서 수정. 점수 공식·임계·가중치·상한 불변, 코퍼스 16종 점수 불변.
- 누락 수정 — 헤더 전용 C++:
.h는 기존에 "c"로 분류돼 헤더의 C++ 클래스가 타입 내부 지표(SIZE-04 god type·ARCH-08 DIT·ARCH-07 LCOM4)에서 누락됐다. 이제.h에 C++ 마커(namespace/template/class/std::/접근지정자)가 있으면 cpp로 분류한다(cpp 프론트엔드가 c도 처리하므로 함수 추출은 불변; 순수 C 헤더는 마커가 없어 그대로 c). 효과: fmt이 cpp:81%로 인식되고 format.h의 클래스가 분석된다(god class는 없어 점수 불변, 커버리지만 정정). - 과탐 수정 — 벤더링 JS: minified/번들 JS를 generated로 보고 분석에서 제외. 이름(
-min.js/.min.js— 대시 변형 추가)과 내용(라인 길이 >2KB) 둘 다로 감지. 효과: govwa의jquery-3.2.1-min.js(findings 72→0) —-min.js(대시)라 기존.min.js필터를 빠져나가던 것. govwa는 SEC critical cap이라 79/C 불변. - 검증: 코퍼스 16종 전부 동일 등급·점수(govwa 79/C, cpp-fmt 95/A, c-linenoise c:100%·84/B). 추출 audit으로 7개 언어 함수 추출이 모두 정상 작동함을 확인(점수 높은 게 under-detection이 아님을 입증).
- 테스트:
TestScanCppHeaderClassification,TestScanMinifiedJSExcluded.
v10.0.0 (2026-06-14)
MAJOR — god-type 극단 상한(docs/03 §2.9) 신규 점수 규칙. §2.8(ARCH 결합)과 동급. SIZE-04 god type을 점수에 반영하되, 오탐 없이.
- 문제: SIZE-04 god type은 메서드 수(≥30)로 잡는데, 30~100 구간은 정당한 fluent/builder API가 사는 곳이라 약한 신호다. cs-stateless(best, 92/A)의
StateConfiguration(85,.Permit()오버로드)이 sepilotdChannelMessagePipeline(79)보다 메서드가 많다 — 숫자가 겹쳐 단순 개수 cap은 잘 만든 라이브러리를 오탐 강등시킨다. - 해결: 메서드 수가 *명백한* god-class 신호가 되는 극단(≥100메서드)만 SIZE 카테고리에 상한 — 1개→89, ≥2개→79. 30~100 구간은 밀도 점수만(리포트엔 계속 노출). 근거: Lanza-Marinescu(2006) god class = WMC+cohesion인데 JAM은 메서드 수만 보므로 count-only는 극단에서만 점수화하는 게 정직. god file(최상위 선언 ≥100)은 "God Type" 메시지 토큰으로 구분해 미발동.
- 캘리브레이션 검증: 16종 코퍼스 + 실프로젝트 중 ≥100메서드 타입 보유는 sepilotd뿐(DaemonClient 320, SqliteSemanticIndex 107) → SIZE 99→79, 총점 82→80/B. cs-stateless(최대 85)·전 코퍼스 불변 — fluent API 보호 확인.
- 테스트:
TestGodTypeExtremeCeiling,TestGodTypeBelowExtremeNoCeiling(cs-stateless 85 보호),TestGodFileNotMistakenForGodType.
v9.0.0 (2026-06-14)
MAJOR — ARCH 결합도 집중 상한(docs/03 §2.8) 신규 점수 규칙 추가(v7.0.0 SEC 상한·v8.0.0 집중 가드와 동급의 score-affecting 규칙). 더불어 리포트에 아키텍처 원시 신호를 노출.
- 문제: SQALE 밀도와 §2.7 비율 가드 둘 다 대형 코드베이스에서 *결합 결함 집중*을 희석한다. sepilotd는 Ce 최대 44짜리 god-module 5개 + 순환 1개를 가졌는데 debt 밀도(457분/70만 LOC, TDR 0.0002) → ARCH 100, 고위험 비율 0.2%(<30%)라 §2.7 가드도 무발화 → "ARCH 100"이 실재 결합 집중을 가림.
- B(점수 규칙): 심각 결합 violation(ARCH-03 Ce>임계, ARCH-05 허브, ARCH-06 변경파급)의 절대 개수로 ARCH 카테고리에 상한 — 1~2건이면 89, ≥3건이면 79(C 밴드). 비율이 아니라 개수라 대형 repo에서 안 희석. 순환(ARCH-01)은 제외(BigCycle 등급캡으로 별도 처리; 소형 순환 1건은 fmt·hyperfine 등 양성 사례라 캡 대상서 빼야 캘리브레이션 유지). 근거: 불연속 아키텍처 스멜(Arcan/Fontana 2017), SIG risk-profile의 집중 집계(Heitlager 2007/Alves 2010/Baggen 2012).
- A(리포트): ARCH 섹션에
원시 신호(밀도 점수와 별개): 순환 N · 결합과다 N · 허브 N · 변경파급 N라인을 항상 노출 — 점수가 희석돼도 SAM식 원시 카운트(MCD/CBO/GM 대응)는 보이게. - 캘리브레이션 검증: 16종 코퍼스 best/stress 중 ARCH-03/05/06 violation 보유 샘플 0개(전부 ARCH-01 순환뿐) → 코퍼스 점수 전부 불변. 과결합 실프로젝트만 발화: sepilotd ARCH 100→79, 총점 87→82/B. rust-hyperfine(98)·cpp-fmt(100)·pygoat·dvcsharp·rustlings는 순환만 있어 무영향(회귀 0). race-clean.
- 테스트:
TestArchCouplingConcentrationCeiling,_SoftCeiling,TestArchCycleAloneNoCeiling,TestArchCouplingWarningNoCeiling.
v8.10.0 (2026-06-14)
MINOR — TypeScript/JavaScript용 함수 내(intra-procedural) taint 분석을 SEC-07(경로 조작, CWE-22)·SEC-08(SSRF, CWE-918)에 추가. 소스→싱크 데이터플로우(표준 SAST 기법). 코퍼스 16종 점수 불변.
- 문제: 기존 라인 기반 SEC-07/08은 사용자 입력 토큰이 싱크 인자 안에 있어야만 발화 → 입력을 지역 변수에 먼저 담는 흔한 다중 라인 패턴(
const id=req.query.id; const p="./f/"+id; fs.readFile(p))을 놓침(룰 주석에 한계로 명시돼 있던 부분). - 해결:
treesitter.TypeScriptTaint— TS AST에서 함수 스코프별로 변수 taint를 전방 전파(할당·concat·템플릿·멤버 접근). 확정된 흐름은 violation·high로 보고(라인 기반 same-line의 warning·low 대비 격상 — 추적된 소스→싱크 경로가 토큰 근접보다 강한 근거). - 정밀도 우선(오탐 0): 전파가 모든 call_expression에서 중단 → 새니타이저(
path.basename/encodeURIComponent/DOMPurify.sanitize등)·미지의 헬퍼가 taint를 자동으로 끊는다(allow-list 불필요). 또한 싱크 인자에 이미 소스 토큰이 있으면 라인 기반 룰의 몫으로 두어 이중 보고 없음(엔진이 강제). 함수 경계를 넘지 않음(intra-procedural). - 검증: 단위 8종(다중 라인 SEC-07/08 발화, 새니타이저·재할당·스코프 격리·소스-직접-인자 미발화) + E2E 실증(Express 합성 앱:
req.query.file→full→fs.readFileSEC-07,req.body.url→템플릿→axios.getSEC-08 발화;path.basename케이스 무발화). 코퍼스 16종 + gitops-console/sepilotd 점수 전부 불변(다중 라인 path/SSRF 흐름 부재 — nodegoat의 fs 싱크는 전부 리터럴 cert 경로). race-clean. - 테스트:
TestTaint_SEC07_MultiLineFlow,_SEC08_TemplateFlow,_SanitizerBreaksChain,_ReassignClears,_DirectSourceDeferredToLineRule,_ScopeIsolation,_NoSourceNoFinding,_JavaScript.
v8.9.0 (2026-06-14)
MINOR — 타입 내부 지표를 C++·Rust로 확장. SIZE-04(God Type)은 두 언어 모두, ARCH-08(DIT)은 C++(Rust는 상속 없음 → N/A). 코퍼스 16종 점수 불변.
- C++ god type + DIT:
cpp.wasm문법 추가. 클래스 =class_specifier·struct_specifier(C++의 struct는 클래스), 본문 =field_declaration_list. 메서드 =function_definition(인라인) 또는 declarator가function_declarator인field_declaration/declaration(프로토타입·생성자·소멸자) — 데이터 멤버(field_identifierdeclarator)와 정확히 구분. 상속 =base_class_clause의 첫type_identifier(템플릿/스코프 베이스는 체인 종료 → 과대계상 없음). - Rust god type:
rust.wasm문법 추가. Rust 메서드는 struct 본문이 아니라 별도impl블록에 있으므로 타입명으로 inherent impl(impl Type)의function_item을 합산하는 전용 추출기(rustGodClasses) 사용. trait impl(impl Trait for Type)은 인터페이스 적합이지 타입 고유 책임이 아니므로 제외(보수적·오탐 감소). 파일 단위 집계(타 파일 impl은 합산 안 함 — 타 언어와 동일 범위). Rust는 상속이 없어 ARCH-08 DIT는 N/A. - 사전필터·테스트 규칙:
class키워드가 없는 C++ struct/Rust를 위해 언어별 사전필터 추가(C++class|struct, Rustimpl). 테스트 제외 규칙에 GoogleTest*_test.cc/*_unittest.cc, Rustbenches/추가. - 검증: 실 코드 추출 확인(fmt
format.h64개 타입 추출 — bigint 16메서드·uint128 10·format_int 10; hyperfinecommand.rsCommand 9·Commands 6). 모두 30 미만이라 god type 미발화 — 진짜 음성(silent failure 아님). 코퍼스 cpp-fmt 95/A·cpp-fuzzer 79/C·rust-hyperfine 92/A·rust-rustlings 87/B·c-linenoise 84/B·c-how2heap 94/A 전부 불변. C는 클래스가 없어 전부 N/A. race-clean. - 테스트:
TestGodClasses_CPP,TestGodClasses_Rust,TestSIZE04_CppGodClass,TestSIZE04_RustGodType,TestARCH08_CppDeepChain.
v8.8.0 (2026-06-14)
MINOR — 타입 내부 지표(SIZE-04 God Type, ARCH-08 DIT)를 C#으로 확장. C# 프로젝트만 신규 findings가 생기고, 비-C# 코퍼스 15종 점수는 불변.
- C# 문법 추가:
csharp.wasm을 wasi-sdk로 빌드해 임베드. 노드타입 —class_declaration/method_declaration·constructor_declaration(메서드 카운트) /base_list(상속).base_list의 첫 항목을 베이스 클래스로 본다(class Derived : Base, IFoo→ Base 관례). 인터페이스만 상속하는 경우(class Leaf : IService)는 클래스로 해석되지 않아 체인이 무해하게 종료 → 과대계상 없음. - 문법 임베드 gzip 압축: TS·Java·Python·C# 4종 문법을
*.wasm.gz로 임베드(~4배 축소, 첫 컴파일 시 1회 gunzip). 문법 3종 raw(~14MB) → 4종 gzip 바이너리 ~12MB. - 테스트 파일 제외 보강:
.NET의*.Tests/*.Test프로젝트 디렉터리 관례를isTestFile이 인식 — xUnit fixture(예:test/Stateless.Tests/StateMachineFixture.cs,[Fact]메서드 다수)가 god type으로 오인되지 않는다. C# 접미사*Test.cs·*Tests.cs도 추가. - 검증:
dotnet-state-machine/stateless92/A — 실제 god type 3건(StateConfiguration 85·67메서드, StateMachine 46) 검출, 테스트 fixture 오탐 0.appsecco/dvcsharp-api79/C(SEC-critical cap 유지). 비-C# 코퍼스(ts-is 89/B·gs-rest 100/A·dvja 79/C·pygoat 79/C) 전부 불변. race-clean. - 테스트:
TestSIZE04_CSharpGodClass,TestARCH08_CSharpDeepChain,TestARCH08_CSharpInterfaceOnlyNoChain, 그리고.Tests디렉터리 제외 케이스.
v8.5.0 (2026-06-14)
MINOR — jam-full test scoring에 TEST-SOURCE-COV를 추가하고 test 하위 지표 가중치를 재조정했다. line coverage가 높아도 coverage file이 문서/설정/data뿐이면 테스트 근거로 인정하지 않는다.
- TEST-SOURCE-COV:
coverage.files의 coverable lines 중 소스 확장자(.go,.ts,.py,.java,.rs,.c/.cpp,.cs등)가 차지하는 비율..md,.yml,.json,.toml,.xml,.html,.css,.lock등은 non-source로 본다. path 확장자를language필드보다 우선해 upstream language 오분류를 방어한다. - hard cap: coverable lines가 1K 이상이고 source line 비율이 20% 미만이면 test 컴포넌트 최대 50점, 70% 미만이면 최대 75점. per-file coverage가 없으면
not_assessed로 두고 cap하지 않는다. - reason 보정: 실행 테스트가 0개인 coverage-only report는 density/source gate가 덮어쓰지 않고
no_test_evidencereason을 유지한다. - 효과 (jam v0.24.0 로컬 실측):
sepilotd는 100% line coverage였지만 coverage files가 48 md + 1 yml + 1 json이라TEST-SOURCE-COV=0, test 70→50, full 61→56.gitops-console/jpad-web는 source mix 100%라 source cap 없음.jpad-web는 coverage-only 상태를no_test_evidence로 분류. - 테스트:
TestTestScoreCapsNonSourceCoverageOnLargeSurface,TestTestScoreDoesNotCapMissingPerFileSourceMix,TestRunClassifiesCoverageOnlyReportAsNoTestEvidence.
v8.7.0 (2026-06-14)
MINOR — ARCH-08 깊은 상속(DIT, Chidamber & Kemerer 1994) 추가. import 그래프·응집도에 이어 아키텍처의 *상속* 차원을 측정한다. 코퍼스 점수 불변(실 프로젝트엔 깊은 내부 상속이 드물어 0건).
- ARCH-08 DIT: 프로젝트 내부 상속 체인 깊이 ≥5인 클래스를 보고(경고·확신 medium). TypeScript(
class_heritage→extends_clause)·Java(superclass) tree-sitter 추출. - 정확도 우선(오탐 0): 조상은 *프로젝트 내부에서 모호하지 않게 해석되는 경우만* 카운트 — 외부 프레임워크 베이스(예: React.Component)나 동명 클래스 2개는 체인을 종료해 과대계상 없음. Go(상속 없음)·Python(다중상속) 제외.
- 검증: TS·Java 6단계 체인(DIT 5) 발화, 얕은 체인·외부 베이스 무발화. 실 프로젝트(gitops·sepilotd·ts-is·dvja·gs-rest) ARCH-08 0건(깊은 내부 상속 부재 — 현대 코드는 합성 선호) → 점수 전부 불변, 오탐 0.
- 비고: 추상도(Martin's D)는 Go/TS 관용상(구체+안정 패키지가 정상) 오탐 위험이 커 보류.
- 테스트:
TestARCH08_TypeScriptDeepChain,_ShallowNoFinding,_ExternalBaseStopsChain,_JavaDeepChain.
v8.6.0 (2026-06-14)
MINOR — SIZE-04(God Type)을 Java·Python으로 확장(Go·TypeScript에 이어). 메서드 ≥30 클래스를 tree-sitter로 잡는다. 코퍼스 점수 불변(Java/Python 샘플에 god-class 없음).
- 문법 추가:
java.wasm(0.68MB)·python.wasm(0.72MB)을 wasi-sdk로 빌드해 임베드. 바이너리 ~14MB(문법 3종). C#(6MB)은 크기상 보류. - 다언어 공통화:
treesitter.GodClasses(lang, src)(언어별 노드타입 config — TS method_definition / Java method·constructor_declaration / Python function·decorated_definition) +tsclass.EachGodClass(병렬·테스트파일 제외, Java*Test.java·Pythontest_*.py등 추가). 메서드 수만 세므로 언어 무관하게 견고; 필드 응집(ARCH-07)은 언어별 필드접근 해석이 필요해 TS 한정 유지. - 검증: Java/Python 합성 30-메서드 클래스 발화, 소형·테스트파일 무발화. 실 코드 추출 검증(dvja HelloWorld 3메서드, pygoat Django admin 0메서드 정확). 코퍼스 Java/Python 4종 점수 불변, 오탐 0. race-clean.
- 테스트:
TestSIZE04_JavaGodClass,TestSIZE04_PythonGodClass.
v8.4.0 (2026-06-14)
MINOR — SIZE-04(God Type)을 TypeScript로 확장. import 그래프 ARCH 메트릭과 LCOM4 응집도가 *못 잡는* 대형 TS 클래스(중앙 필드로 연결돼 LCOM상 응집적인 god-class)를 크기 기준으로 잡는다. tree-sitter 기반(v8.3.0 인프라 재사용). 코퍼스 16종 점수 불변(유일 TS 샘플 sindresorhus/is에 god-class 없음).
- SIZE-04 TS god type: TS 클래스의 메서드 ≥30이면 violation(Go struct와 동일 임계 godDeclThreshold=30).
tsclass.EachClass(tree-sitter, 병렬·테스트파일 제외)로 추출. - 공통화: TS 클래스 추출을
treesitter.TypeScriptClasses(필드·메서드·this.x 접근)와internal/analyze/tsclass.EachClass(프로젝트 단위 병렬 오케스트레이션)로 분리 → ARCH-07·SIZE-04가 공유, 향후 추상도/상속도 재사용. ARCH-07 동작 보존(테스트 통과). - 효과 (jam v0.23.0 로컬 실측): 코퍼스 16종 + gitops/ts-is 점수 불변(god-class 없음). sepilotd에서 god-class 9건 신규 검출 — DaemonClient(메서드 320), SqliteSemanticIndex(107), ChannelMessagePipeline(79) 등. 점수는 밀도상 소폭(SIZE 99; 2858파일 중 9개=0.3%) — 신호는 리포트에 명확히 노출.
- 테스트:
TestSIZE04_TypeScript{GodClass,SmallClassOK,TestFileExcluded}; tsclass 병렬 race-clean.
v8.3.0 (2026-06-14)
MINOR — ARCH-07(낮은 응집도 LCOM4)을 TypeScript로 일반화. v8.2.0의 go/ast 전용 구현을 언어 중립 평가기로 분리하고 tree-sitter 백엔드를 추가 — ARCH가 비-Go 언어에서도 "타입 내부 구조"를 본다. 새 finding 가능하나 코퍼스 16종 + gitops/sepilotd 점수·등급 전부 불변(보수적 게이트, 실 TS 클래스는 LCOM-응집적).
- tree-sitter 통합: tree-sitter-typescript 문법을
wasm32-wasi(wasi-sdk)로 컴파일해 임베드, 순수 Go wazero 런타임으로 구동 → CGO_ENABLED=0 정적 빌드 유지. emscripten·CGo 둘 다 회피(docs/08 M2). JAM 최초의 외부 의존성(wazero).internal/treesitter패키지. 바이너리 +~1.7MB. - 언어 중립 LCOM4:
evaluateLCOM(lcomCandidate)가 Go(go/ast)·TS(tree-sitter) 백엔드를 동일 게이트로 채점. TS는class_declaration→public_field_definition(필드)·method_definition(메서드) → 메서드 본문의this.<field>member 접근으로 필드/형제호출 해석. - 정확도 우선(오탐 0) 유지: Go와 동일 게이트(참여 메서드 ≥5·필드 ≥4·실질 클러스터 ≥2). TS 테스트파일(
.test.ts/.spec.ts/.d.ts/__tests__) 제외.class정규식 사전필터 + 파일 병렬 파싱(race-clean). - 검증: 합성 2-책임 TS 클래스 정확 발화(comps=2), 응집 TS 클래스·테스트파일 무발화. 실 TS 추출 검증 — sepilotd
ChannelMessagePipeline(필드 16·메서드 79)을this.field/this.method()까지 정확 추출. 그럼에도 ARCH-07 0건: 대형 클래스도 중앙 필드(runtime)+공유 헬퍼로 1개 응집 그룹 → LCOM4상 응집적(god-class-by-size는 별개 신호). 즉 0건은 정확한 true negative. - 효과 (jam v0.22.0 로컬 실측): 코퍼스 16종 + gitops/sepilotd/ts-is 점수 전부 불변. tree-sitter 파싱은 성능에 무영향(sepilotd 707k LOC 스캔 시간은 기존 DUP/CPLX 분석이 지배, TS 203 클래스파일 파싱은 무시 가능).
- 테스트:
TestARCH07_TypeScript{TwoCluster,Cohesive,TestFileExcluded};internal/treesitter파싱·구조추출 테스트. 기존 Go ARCH-07 테스트 전부 통과(리팩터 동작 보존).
v8.2.0 (2026-06-14)
MINOR — ARCH가 import 그래프(물리적 결합) 한 관점만 보던 한계를 넘어, 타입 내부 구조를 보는 첫 메트릭 추가. 새 finding 가능하나 코퍼스 16종 + gitops/sepilotd 점수·등급 전부 불변(Go 전용 + 실 Go 코드 오탐 0).
- ARCH-07 낮은 응집도 (LCOM4, CWE 없음 / Hitz & Montazeri 1995): 한 타입의 메서드가 상태를 공유하지 않는 2개 이상 독립 응집 그룹으로 분리되면 보고(경고·확신 medium). 의존성 그래프엔 안 보이는 "한 타입에 무관한 책임 다발" 신호.
- go/ast 전용 (Go 한정): 타입 구조(필드·메서드·필드 접근)는 진짜 AST가 필요. 다른 언어는 tree-sitter WASM 프론트엔드(docs/08 M2) 도입 후 확장 예정 — 현 lexer 프론트엔드는 필드 접근을 못 봄. lang.go가 명시한 폴백 한계.
- 정확도 우선 설계(오탐 0 목표): 정적 분석 도구이므로 명백한 분리에만 발화. (a) 필드 접근/형제 호출 메서드만 참여(커넥터 유지로 거짓 분리 방지), (b) 실질 클러스터(≥2 메서드 + 실제 로직 메서드 — 필드 2개↑ 또는 형제 호출)가 ≥2개일 때만 → getter/setter 쌍·DTO·데이터 클래스 구조적 제외, (c) 메서드 ≥5·필드 ≥4, (d) 임베디드/승격 무시, 테스트 파일 제외.
- 검증: 합성 2-책임 타입(auth+metrics)에 정확히 발화(comps=2), accessor-pair DTO·응집 타입·소형 타입엔 무발화. 실 Go 프로젝트(jam·govwa·go-cleanhttp) ARCH-07 0건(진짜 응집적) → 코퍼스 18종 점수 전부 불변. arch 커버리지 유지.
- 동기: "ARCH가 의존성 그래프만 본다"는 지적을 수용. import 그래프가 희소해 ARCH≈100인 것은 risk-profile로 정당화됐으나(v8.0.0), 응집도/추상도/상속 같은 *그래프 밖* 축은 별도 신호. LCOM4부터 go/ast로 시작(로드맵 철학: 추상화 전 한 언어에서 메트릭 검증).
- 테스트:
TestARCH07_TwoClusterGodType,_CohesiveNoFinding,_DTONoFinding,_AccessorPairsNoFinding,_SmallTypeNoFinding,_NoFieldMethodExcluded.
v8.1.0 (2026-06-14)
MINOR — SEC 탐지 범위(recall) 확장. 대형 웹앱 측정에서 JAM이 룰 자체가 없어 못 보던 보안 클래스(SSRF·XSS·경로조작)를 실증 확인하고 메트릭을 추가. 새 finding이 생길 수 있으나 코퍼스 16종 점수·등급 전부 불변(정밀도 게이트; SEC recall finding은 이미 캡된 취약앱에만 떨어짐). v6.1.0과 동일 패턴.
- SEC-06 Client-Side Injection / DOM XSS (CWE-79):
dangerouslySetInnerHTML(React 이스케이프 우회 싱크 — 항상 보고),.innerHTML/.outerHTML =·document.write(·.insertAdjacentHTML(에 비리터럴 값 전달(violation, JS/TS). 정적 리터럴 마크업은 제외. 근거 CWE-79, OWASP DOM-XSS. - SEC-07 Path Traversal (CWE-22): 파일 싱크(readFile/createReadStream/createWriteStream/writeFile/sendFile/unlink/appendFile)에 사용자 입력 토큰(req/request/params/query/body/argv/searchParams/headers/nextUrl/formData)이 포함된 동적 경로 전달. recall 지향이라 warning·확신낮음(half-debt, SEC 상한 미발동). 입력 토큰을 인자에 요구해 오탐 폭주 방지(sepilotd 1161→5). 근거 CWE-22.
- SEC-08 SSRF (CWE-918): HTTP 클라이언트(fetch/axios/got/superagent, http(s).get·request 등)에 사용자 입력 토큰이 포함된 동적 URL 전달. warning·확신낮음, 동일 입력-토큰 게이트(sepilotd 139→3). 근거 CWE-918, OWASP SSRF.
- SEC-04 확장:
execSync(셸 기반) 추가, Pythonos.system(·subprocess.*(shell=True)추가. 안전한spawn/execFile(배열형)은 일부러 제외(precision). - RES-01 키워드 확장: C/C++
fopen→fclose누락(흔한 파일 핸들 누수), Go acquirer에net.DialTimeout/DialTCP/DialUDP/ListenTCP/ListenUDP·tls.Dial/Listen추가. - 동기(실증): gitops-console·sepilotd에 dynamic-fetch(SSRF 후보 135), dangerouslySetInnerHTML(XSS 4), readFile(입력) 등 JAM이 0개 룰로 못 보던 패턴 다수 확인. SEC 룰은 SEC-01~05뿐이라 SSRF/XSS/경로조작 탐지가 0이었음.
- 효과 (jam v0.20.0 로컬 실측): 코퍼스 16종 + gitops/sepilotd 점수·등급 전부 불변. 신규 finding은 sepilotd(SEC-06×4, SEC-07×5, SEC-08×3, RES fopen 등)·취약앱(govwa/pygoat XSS, 이미 SEC=25)에만. 양성 대조군(ts-is 등) 신규 SEC violation 0건. cpp-fuzzer RES 99→97(실제 fopen 누수 1건, 총점 79/C 불변).
- 테스트:
TestSEC06_XSS,TestSEC07_PathTraversal,TestSEC08_SSRF,TestSEC04_BroadenedExec, RES fopen 케이스 추가. sec 99.3%·res 98.6% 커버리지.
v8.0.0 (2026-06-14)
MAJOR — SIG 모델 risk-profile 진단 + 벤치마크 도출 집중 가드 (docs/03 §2.7). 새 점수 규칙(가드)이 추가되므로 규약상 MAJOR. 단 현 코퍼스 16종 + gitops/sepilotd 점수·등급 전부 불변(가드 dormant — 밀도가 이미 포섭).
- risk profile 진단 (점수 불변, 리포트 부록 A): 카테고리별 심각도 분포(info/warning/violation/critical) + size-independent 고위험 집중도 =
violation·critical finding을 가진 고유 파일 수 / 전체 파일 수. JSONcategories[].highRiskFiles/highRiskShare에도 기록. 밀도 점수를 "위험이 실제로 얼마나 집중됐는지"와 나란히 읽게 한다. - 집중 가드 (점수 영향, 벤치마크 도출): 한 카테고리의 고위험 파일 비율 ≥ 30%(파일 20개↑ 프로젝트)면 밀도가 아무리 size로 희석돼도 그 카테고리는 깨끗한 A를 제시 못 함 → 점수 상한 79(C 밴드).
metrics.ConcentrationGuard{Share,MinFiles,Cap}. - 임계 도출(벤치마크): 16종 코퍼스에서 밀도 ≥90 카테고리의 고위험 비율은 (소형 아티팩트 제외) ~12% 미만, 30% 초과 케이스는 이미 밀도가 낮게 매김(예 33% DUP = 59점). 30%는 정상의 ~2.5배 너머 → 현 코퍼스 무발화, 미래 병적 집중만 잡는 안전망. 소형 프로젝트 % 노이즈는 20-파일 게이트로 차단.
- 근거(문헌, docs/03 §2.7, §8): SIG/TÜViT — Heitlager 2007(QUATIC), Alves 2010(ICSM), Baggen 2012(SQJ). 검증된 명제(verbatim): "averaging to aggregate measures on individual system parts tends to mask the presence of high-risk parts" → 평균 대신 risk profile + 벤치마크 임계 처방(deep-research 적대 검증 3-0 통과). SIG식 *전면 점수화*(밀도→risk-profile 교체)는 상대 점수화·설명가능성(§1) 재정의를 수반해 거부 — JAM은 검증된 SQALE 밀도를 유지하고 risk profile은 진단+가드로만 도입(SonarQube와 동일 절충).
- 발견: risk profile이 점수를 반박이 아니라 정당화 — sepilotd ARCH=100은 고위험 0.2%(2858 중 6 파일)라 희석이 아니라 진짜 깨끗; 실제 고집중(DUP 24~33%)은 이미 밀도가 낮게 매김. 즉 "숨은 희석"은 없었고 가드는 dormant.
- 효과 (jam v0.19.0 로컬 실측): 코퍼스 16종 + gitops·sepilotd 점수·등급 전부 불변(가드 미발화; 최고 클린-카테고리 비율 sepilotd DUP ~24% < 30%). risk profile은 모든 리포트 부록 A에 신규 표시.
- 테스트:
TestRiskProfileComputed(고유 고위험 파일·비율),TestConcentrationGuardFires(35%→상한 79),TestConcentrationGuardDormantBelowThreshold(25%→무발화),TestConcentrationGuardSkipsSmallProjects(파일<20 면제). 전체 스위트 green.
v7.0.0 (2026-06-13)
MAJOR — worst-case SEC 카테고리 상한 + 등급 캡 총점 클램프. 단일 치명 결함이 밀도 정규화에서 희석돼 "총점은 높은데 등급은 C" 가 되던 모순을 없앤다. 점수 모델 변경이므로 코퍼스 재핀.
- SEC worst-case 상한 (docs/03 §2.6): SEC 카테고리 점수에 밀도와 무관한 절대 상한을 둔다 — 가장 심각한 SEC finding 이 critical 이면 SEC ≤ 25, violation 이면 SEC ≤ 60, warning/info 면 상한 없음.
category score = min(밀도 점수, 상한). 70만 LOC 프로젝트의 시크릿 1건이 debt 밀도로 반올림 오차가 돼 SEC 가 ~100 으로 남던 문제를 해결. - 등급 캡 총점 클램프 (docs/03 §2.5): 하드 등급 캡(SEC critical→C, big-cycle→B, 파스 실패→C)이 등급을 낮추면 표시 총점도 밴드 상한(C 79·B 89·D 64·F 49)으로 함께 내린다. 자연 등급이 이미 캡 이하면 총점 불변.
metrics.GradeBandTop. - SEC 만 worst-case 로 취급: 누적형 차원(CPLX·SIZE·DUP·HYG, ARCH 결합)은 밀도 유지(실증상 크기 일관적). 순환(ARCH-01)·파스 실패는 기존 등급 캡으로 충분 — 소형 순환(SCC 2~3)에 카테고리 상한을 걸면 헤더 전용 라이브러리(fmt) 등을 오탐 강등시킨다. RES 도 밀도 유지(RES-01 은 정밀도 한계로 가중치 0.08 인 휴리스틱; 상한으로 증폭하면 테스트 파일
new/malloc오탐을 처벌). 시뮬레이션으로 순환·RES 상한이 cpp-fmt·hyperfine·rustlings 를 한 등급씩 부당 강등함을 확인하고 범위에서 제외. - 동기: 80364 CLOC gitops-console·706856 CLOC sepilotd 측정에서 SEC violation(하드코딩 비번 등)이 있는데도 SEC 100·총점 A 로 나왔고, java-dvja 는 총점 98 인데 등급 C 였다. 보안은 JAM 이 이미 worst-case 로 취급(critical→C 캡)하는 유일 차원이라 violation 이 100 으로 표시되는 건 내부 모순.
- 근거(문헌, docs/03 §2.6): 가중 평균의 치명 결함 은폐 — Fenton & Pfleeger, *Software Metrics*. 크기 교란 → 누적형은 정규화 필수 — El Emam et al. 2001(IEEE TSE); 밀도=SQALE TDR — Letouzey 2012. 보안 결함의 worst-case 처리는 업계 표준 — SonarQube Security/Reliability Rating(Blocker 1건→최저 등급), CVSS base score("reasonable worst-case"). (OWASP Risk Rating은 요인 평균이라 worst-case 아님 — 보편 규칙으로 일반화 금지.) 규모 보상 분모 거부 — Boehm COCOMO II(E>1). critical 일괄 cap/가중을 거부한 이유: JAM 은
critical을 누적형 임계(CPLX-01 CCN≥50, SIZE-01 file≥2000, DUP-01 ≥20%)에도 쓰므로 일괄 처리 시 우수 라이브러리(fmt 등)를 오탐 강등 — 시뮬레이션으로 cpp-fmt 95/A→77/C 확인, worst-case 차원(SEC)에만 적용. - 효과 (jam v0.18.0 로컬 실측, 코퍼스 16종): SEC-critical 취약 앱 6종(govwa·js-nodegoat·py-pygoat·java-dvja·cs-dvcsharp·cpp-fuzzer)이 94–98/C → 79/C 로 숫자=등급 정렬. py-itsdangerous 98/A → 90/A(sha1 SEC-03 violation), sindresorhus/is 97/A → 89/B(테스트의
new Function(SEC-04 violation — 유일한 best-project 등급 변화). SEC 이슈 없는 클린 라이브러리(cpp-fmt 95/A·hyperfine 92/A·go-cleanhttp 100/A·java-gs-rest 100/A·cs-stateless 93/A·rustlings 87/B·linenoise 84/B·how2heap 94/A) 전부 불변. 대형: sepilotd 95/A→87/B, gitops 91/A 불변. - 테스트:
TestHardCapSecCriticalWorseThanNatural(상한 25·등급 C·밴드 클램프),TestSecViolationCategoryCapNoGradeCap(상한 60·등급 캡 없음·클램프 없음),TestSecWarningNoCategoryCap(밀도 유지) 추가/갱신. 전체 스위트 green.
v6.1.0 (2026-06-13)
MINOR — ARCH 카테고리에 두 메트릭 추가: 순환이 없어도 결합이 얽힌 아키텍처를 잡는다. 새 finding 이 생길 수 있으나 코퍼스 16종의 기존 점수는 불변(작은 그래프는 평가 안 함).
- ARCH-05 Hub-Like Dependency(허브형 의존 / god component): 구심 Ca·원심 Ce 가 동시에 그래프 평균+2σ outlier 이고
min(Ca,Ce)가 절대 하한(경고 4·위반 8)을 넘는 모듈을 보고. 노드 12개 미만 그래프는 평가 안 함. barrel/재export 파사드(index.*,mod.rs,lib.rs,__init__.py)·순수 집약 노드는 제외. 근거 Arcelli Fontana et al. 2017(Arcan, ICSA). - ARCH-06 Propagation Cost(변경 파급 비용): 전이적 의존(가시성 행렬)의 밀도 = 한 모듈 변경 시 평균 도달 가능한 시스템 비율. 경고 30%·위반 50%, 노드 12개 미만 그래프는 평가 안 함, 그래프당 최대 1건. 근거 MacCormack et al. 2006(Management Science).
- 동기: ARCH 가 코퍼스 거의 전부 100점이던 진짜 원인은 임계값이 관대해서가 아니라 의존성 그래프가 희소(대부분 <40 엣지)해서임을 측정으로 확인. 순환·Ce 임계는 acyclic god-component/과결합을 못 잡는다. 새 메트릭은 큰 god-component 코드베이스(예: 2700파일 TS 모노레포)에서만 발화하고 작은 프로젝트엔 노이즈를 더하지 않도록 그래프 크기 가드를 둠.
- 효과(jam v0.17.0 로컬 실측): 코퍼스 16종 점수·등급 전부 불변(hub FP 0건). govwa(의도적 취약 앱)만 PC 경고 1건(Go 패키지 그래프 PC=34%)으로 정당하게 발화. 외부 대형 TS 모노레포에서 god-component 2건 검출 확인.
- 테스트: ARCH-05 허브 검출/순수 source 제외/barrel 제외/작은 그래프 침묵/위반 등급, ARCH-06 파급 검출/저결합 비검출 단위 테스트 추가. arch 패키지 커버리지 97.9% 유지.
v6.0.0 (2026-06-12)
MAJOR — SEC-04(위험 역직렬화/동적 실행) 를 싱크 인자가 비리터럴일 때 critical 로 에스컬레이션. jam-lite 의 마지막 보안 미탐지 (recall) 공백을 메운다.
- SEC-04 escalation:
eval(,pickle.loads(,yaml.load((unsafe),child_process.exec(,new Function(싱크의 인자가 변수·호출 (비리터럴) 이면 — 예:eval(req.body.x)— 확정 코드 인젝션/안전하지 않은 역직렬화 경로로 보고SevCritical(등급 상한 C). 문자열/숫자 리터럴만 들어가면 — 예:new Function('return 1')—SevViolation유지. 리터럴 판정은nonLiteralArg(sec02_jvm.go) 재사용. - 동기: OWASP NodeGoat 처럼
eval(req.body.preTax)로 사용자 입력을 직접 실행하는 SSJI 앱이 v5.0.0 까지 Grade A(96) 로 남았다 (SEC-04 가 violation/medium 이라 캡 미적용). 이게 jam-lite 의 마지막 후함이었다. - 효과 (jam v0.16.0 로컬 실측): js-nodegoat 96/A → 96/C(SEC-04 critical 캡). py-pygoat 는 이미 C 였으나 SEC-04 6 건이 critical 로 승격. 클린 앱은 불변 — ts-is 는
new Function('return class{};')(리터럴 인자) 이라 violation 유지 → A 그대로. - E2E: js-nodegoat·py-pygoat·java-dvja·cs-dvcsharp·govwa 모두 C 로 재핀. "자연" 가중 등급은 전부 A 이고 SEC critical 하드 캡이 낮춘 것.
- 테스트:
TestSEC04Python/TestSEC04JS에 리터럴 인자 → violation, 비리터럴 → critical 케이스 추가.
v5.0.0 (2026-06-12)
MAJOR — SEC-02(인젝션) 위반 레벨을 violation 에서 critical로 에스컬레이션. Java/C# SQL/명령 인젝션 탐지 추가. SEC critical 하드 캡 (최대 C) 으로 인해 취약한 앱은 등급이 하강한다.
- SEC-02 escalation: 모든 SEC-02 finding 을
SevCritical로 상향. SEC critical 은 등급 캡 C 를 적용하므로, SQL/명령 인젝션이 탐지되면 A/B 는 불가능하다. - Java/C# 탐지 (
sec02JvmNet): - SQL 인젝션: ≥2 SQL 키워드가 동적 문자열 (+ 결합/
String.format/C#$"…{…}"보간) 에 포함. - 명령 인젝션:
Runtime.exec,ProcessBuilder,Process.Start에 변수 전달. - 동기: dvja(99/A)·dvcsharp(95/A)·govwa(94/A) 같은 '일부러 취약한' 앱이 높게 나오는 후함 제거.
- 효과: dvja/dvcsharp/govwa 모두 Grade C 로 하강, 클린 앱은 A 유지.
- 테스트:
TestSEC02Java/TestSEC02CSharp추가, 기존 SEC-02 테스트는SevCritical로 갱신.
v4.0.0 (2026-06-12)
MAJOR — 점수 보정. TDRMax 를 0.20 에서 0.10으로 낮춰 SQALE 희석 민감도를 2 배로 한다. 카테고리 점수 = 100 × (1 − TDR/TDRMax)인데, 0.20 에서는 dev-cost 의 20% 에 달하는 부채가 있어야 0 점이라 현실 부채 (TDR < 0.05) 가 거의 표시되지 않아 모든 프로젝트가 85–100 에 뭉쳤다. 0.10 에서는 실제 유지보수성 부채가 등급을 가른다.
- 동기: 17 개 프로젝트 실측에서 깨끗한 라이브러리부터 고복잡도 실제 앱까지 전부 88–100 에 몰렸다. 큰 함수 (CCN 74)·중복이 규모에 희석돼 거의 안 아팠다.
- 효과 (jam v0.13.0 로컬 실측): backup-manager(실제 Next.js 앱, critical 28) 88/B → 75/C, rust-rustlings 94/A → 87/B, c-linenoise 92/A → 84/B. 깨끗한 라이브러리는 A 유지 (go-cleanhttp 100, ts-is 97, py-itsdangerous 98, cpp-fmt 95).
- 한계: 이 보정은 유지보수성 후함만 고친다. 코드가 단순·깔끔하지만 취약한 앱 (java-dvja 99/A) 은 여전히 높다 — 그건 보안 미탐지 (recall) 문제로, 룰 추가가 필요하지 희석 보정으론 못 고친다.
- E2E: 16 개 샘플 재핀 (rust-rustlings·c-linenoise A→B). 코퍼스 헤더의 v4.0.0 관측값 참조.
- 테스트:
TestCategoryScoreFormulaAndClamp(240 분→TDR 0.02→80),TestTotalIsWeightedSum(TDR 0.05→50, Total 90) 갱신.
v3.0.0 (2026-06-11)
MAJOR — 점수 모델 변경. 한 카테고리의 룰셋이 프로젝트의 어떤 언어도 평가하지 못하면, 그 카테고리에 공짜 100 점을 주지 않고 점수에서 제외한 뒤 가중치를 나머지 (평가 가능한) 카테고리로 재정규화한다. 측정하지 못한 차원이 총점을 떠받치던 왜곡을 제거한다.
- 동기: JS/TS 프로젝트는 RES(자원 누수) 에 해당 룰이 전혀 없어 항상 RES=100 을 받았고 (가중치 0.08), 이로 인해 실제 부채 (복잡도·중복) 가 큰 프로젝트도 점수가 부풀려졌다. 실측: 한 Next.js/TS 앱 (critical 28, Dup 64) 이 88/B → 87/B.
- 적용성:
metrics.CategoryLanguages— RES 는go, python, c, cpp, rust만 평가 가능 (JS/TS/Java/C# 제외). 나머지 카테고리는 전 언어 지원이라 변동 없음. Go 프로젝트 점수는 불변(RES 계속 평가). - 동작:
score.ComputeScoped가 프로젝트 언어 집합 기준으로 평가 불가 카테고리를Result.NotAssessed로 분리하고Order/가중치에서 제외 (전부 제외되는 퇴화 케이스는 가드).--only스코핑과는 구분된다. - 리포트: 박스/마크다운에 "측정 불가 카테고리 제외" 안내를 표시한다. 점수는 동일 언어 구성의 스캔끼리 비교한다.
- E2E: JS/TS/Java/C# 샘플의
expected_lite_score_min은 아직 재핀하지 않았다 (코퍼스 노트 참조). - 테스트: TS 전용 프로젝트에서 RES 제외·가중치 재정규화·
NotAssessed검증, Go 프로젝트는 RES 유지 회귀 테스트 추가.
v2.3.4 (2026-06-11)
PATCH — Rust 모듈 그래프에서 facade/re-export 패턴이 대형 순환 캡을 만들던 오탐을 줄였다. 카테고리 가중치와 등급 컷은 바꾸지 않는다.
- ARCH-01: Rust 그래프에서 부모 모듈과 자식 모듈 사이의 계층 엣지는 순환 SCC 입력에서 제외한다.
mod.rs가 child exporter 를 모으고 child 가super::Trait를 참조하는 일반적인 facade 구조가 Grade B cap 을 만들지 않게 한다. - ARCH-03: 같은 Rust 그래프 보정을 공유하므로 Ce/SDP 계산에서도 부모/자식 계층 엣지를 제외한다. sibling 또는 cross-branch 모듈 간 의존은 계속 측정한다.
- E2E 기준선:
rust-hyperfine-best가95/B/153 findings/ARCH cap에서96/A/152 findings/no cap으로 개선됨을 확인했다. - 테스트: Rust facade parent/child edge 는 무시하고, sibling cycle 은 계속 검출하는 회귀 테스트를 추가했다.
v2.3.3 (2026-06-11)
PATCH — 실측 리포트에서 HYG 계열이 문서/테스트 예제와 UI copy 를 과도하게 세던 문제를 줄였다.
- HYG-01: 문서와 테스트 경로는 삼킨 예외/에러 분석에서 제외한다. Markdown 계획서 코드 블록과 테스트용 빈 catch 가 제품 품질 violation 을 만들지 않게 한다.
- HYG-04:
*.config.*,config.*파일은 매직 리터럴 밀도 대상에서 제외한다. - HYG-04: 공백이 포함된 자연어 문자열은 UI/문서 copy 로 보고 매직 문자열 카운트에서 제외한다. 숫자 리터럴과 짧은 코드형 문자열은 계속 측정한다.
v2.3.2 (2026-06-11)
PATCH — 실측 리포트에서 DUP-01 이 테스트 코드와 3~5 라인짜리 조밀한 boilerplate 를 과도하게 violation 으로 만들던 문제를 줄였다. 카테고리 가중치와 점수 모델은 바꾸지 않는다.
- DUP-01: 테스트/fixture/mock 경로를 clone 입력에서 제외한다. 테스트 코드 중복은 제품 코드 품질 점수보다 별도 테스트 유지보수 관점에서 보는 것이 낫다.
- DUP-01: 50 토큰 이상이어도 물리 line span 이 6 라인 미만이면 clone finding 과 중복률 산입에서 제외한다. JSX props/object literal 처럼 토큰 밀도가 높은 짧은 boilerplate 오탐을 줄인다.
- DUP-01: 프로젝트 중복률 분모를 전체 CLOC 가 아니라 실제 DUP 대상 (비테스트, lexable 소스) CLOC 로 계산한다.
v2.3.1 (2026-06-11)
PATCH — gitops-console, sepilotd, security-cli 실측 결과를 바탕으로 false positive 와 노이즈를 줄였다. 점수 산식·카테고리 가중치는 바꾸지 않지만 일부 finding 수와 severity 가 달라진다.
- SEC-01:
__tests__,testdata, 문서, 예제 경로와 placeholder/redacted/{env.VAR}토큰은 warning/low 로 낮춰 보안 hard cap 을 만들지 않는다. URL, 파일 경로, placeholder 변수명, storage key/env var/header/Kubernetes Secret object 이름은 하드코딩 시크릿 후보에서 제외한다. - SEC-03: TLS 검증 비활성화 critical 패턴도 테스트/fixture/문서/example 경로에서는 warning/low 로 낮춰 의도적 bad fixture 가 hard cap 을 만들지 않게 한다.
- SEC-05: LLM 토큰 카운트 (
inputTokens,currentMaxTokens) 와 token id/prefix/note/placeholder 같은 비자격증명 식별자 로깅은 제외한다. - DUP-02: 테스트 파일은 구조적 중복 대상에서 제외하고, 최소 함수 크기를 60 토큰·10 라인으로 올려 작은 UI/테스트 helper 유사도 노이즈를 줄인다.
- HYG-04/05/06: 공통 테스트 경로 분류를 사용해
.test.tsx,__tests__,fixtures,mocks를 테스트 코드로 인식한다.
v2.3.0 (2026-06-11)
MINOR — 남아 있던 jam-lite registry 메트릭 (CPLX-04/05, ARCH-02, DUP-02) 을 구현 활성화. 점수 산식·가중치·기본 비용은 변경하지 않지만, 새 finding 이 추가되어 카테고리/종합 점수가 달라질 수 있다.
- CPLX-04 Halstead Volume 구현: Go scanner 와 언어 공통 경량 lexer 로 연산자/피연산자 기반 파일별 volume 을 산출한다. 직접 debt 는 없고 CPLX-05 입력 및 대형 파일 보조 정보 finding 으로 사용한다.
- CPLX-05 Maintainability Index 구현: Halstead Volume, 평균 CCN, CLOC 기반 VS 정규화 MI 를 파일 단위로 계산한다. 낮을수록 위험한 임계값 (20/10) 을 registry 가 지원하도록
LowerIsWorse를 추가했다. - ARCH-02 Intra-module File Cycle 구현: 동일 디렉터리·언어 버킷의 파일별 정의/참조 심볼 그래프로 SCC 를 찾아 info/medium 으로 보고한다.
- DUP-02 Structural Clone 구현: 함수 단위 정규화 토큰 3-gram 유사도 기반 Type-3 클론 근사를 warning/medium 으로 보고한다. 완전 동일 Type-1/2 는 DUP-01 이 담당한다.
- jam-lite registry 기준 미구현 메트릭이 0 개가 되었다.
v2.2.0 (2026-06-11)
MINOR — HYG-04/HYG-05 구현 활성화. 점수 산식·가중치·기본 비용은 변경하지 않지만, 같은 코드에서 HYG finding 이 추가되어 HYG 카테고리와 종합 점수가 달라질 수 있다.
- HYG-04 Magic Literal Density 구현: import/include, named constant, 테스트 파일, 관용 리터럴을 제외한 파일별 숫자·문자열 리터럴 밀도를 측정한다. 최소 8 건 + 40 건/KLOC 이상 info, 최소 15 건 + 120 건/KLOC 이상 warning 으로 보고한다.
- HYG-05 Comment Density Anomaly 구현: 파일별 주석/CLOC 극단치와 Go 공개 top-level API doc comment 누락률을 측정한다. 과잉 주석, 주석 부재, 공개 API 문서 누락을
HYG-05로 보고한다. - 레지스트리: HYG-04/HYG-05 의
Implemented를true로 전환하고jam metrics, report appendix, SARIF rule 목록에 노출한다.
v2.1.0 (2026-06-11)
MINOR — 기존 메트릭에 C/C++ 제한 지원 언어 규칙 추가. 기본 임계값·가중치·산식 변경 없음.
internal/lang/cpp프론트엔드 추가: C/C++ 소스에서 함수 단위 SIZE-02/03, CPLX-01/02/03, quoted#include "..."import 를 경량 렉서로 추출한다. 전처리기/매크로는 전개하지 않으며 confidence 는 medium 중심이다.- ARCH-01/03: C/C++ 파일 단위 quoted include 그래프 추가. 해석 후보는 포함 파일의 같은 디렉터리, 프로젝트 루트,
include/이며, 미해결 include·시스템 include·매크로 include 는 외부로 처리한다. - RES-01: 함수 로컬
malloc/calloc/realloc↔free,new/new[]↔delete/delete[]짝 검사를 추가한다. 반환된 포인터는 소유권 이전으로 보고 finding 을 내지 않는다. - 공통 분석: C/C++ 파일이 DUP-01, SEC-01, HYG-01/03/06, SIZE-01 에도 참여한다.
cpp-bad픽스처로 ARCH/CPLX/SEC/DUP/HYG/RES 검출을 통합 검증한다.
v2.0.0 (2026-06-11)
MAJOR — 새 메트릭 HYG-07 과 하드 등급 캡이 추가되어 동일 코드의 등급이 달라질 수 있다.
- HYG-07 Parse Failure 추가: Go 파일을
go/parser로 재파싱해 문법 오류를violation/highfinding 으로 기록한다. debt 60 분, rule ref 없음. - 점수 모델: HYG-07 이 1 건 이상이면 등급을 최대 C 로 제한한다. 파스 실패로 AST 기반 메트릭이 누락될 수 있으므로 가중 평균에 희석되지 않게 한다.
- 출력:
ScanInfo.ParseFailures,jam-report.md부록 B,jam-detail.csv,jam-result.json,jam.sarif에 파스 실패가 드러나도록 한다. - CLI v0.6.0 연계:
scan --strict는 리포트 작성 후 파스 실패가 있으면 exit 3,scan --sarif는 SARIF 2.1.0 파일을 생성한다. - 설정:
jam.yaml의metrics.<ID>.warning|violation|critical로 실행별 레지스트리 임계값을 오버라이드할 수 있다. 사용자 오버라이드는 내장 Metrics Spec 버전을 바꾸지 않으며, 산출물에는 적용된 임계값이 기록된다.
v1.2.0 (2026-06-11)
MINOR — 기존 메트릭에 Java/C#/Rust 언어 규칙 추가 (11-metrics-versioning.md §2). 임계값·가중치·산식 변경 없음. 6 개 지원 언어 모두 coverage.
- SIZE-02/03, CPLX-01/02/03: Java/C#/Rust 규칙 추가 —
internal/lang/{java,csharp,rust}경량 렉서 프론트엔드 (퍼지 파싱, lizard 방식). 임계값 동일, confidence 는 medium(퍼지 파싱, Go 경로만 high). - Java: 일반
/* */+//, javadoc, Java 15+ text block, generics/어노테이션 처리. - C#: verbatim
@"…", interpolated$"…{…}"/$@"…", expression-bodied 멤버 (=>),??·nullable 구분,using임포트. - Rust: nested
/* */, raw stringr#…#, lifetime'a와 char literal 구분,?오류 전파 분기, match arm 분기, nestedfn은 별도 단위. - ARCH-01/03:
- Java 패키지 그래프 —
package선언의 역 인덱스 +import해석. 해석 실패는 외부 (오탐 사이클 방지). - C# 네임스페이스 그래프 —
namespace X.Y { … }(블록) 및namespace X.Y;(파일 - 스코프) 모두 수집,using해석. 보수적: 최장 prefix 매치, 미해결 → 외부. - Rust 모듈 그래프 (크레이트 내부) —
mod트리로 파일 매핑,use crate::a::b/use super::x/use self::y해석,mod선언은 엣지 아님 (트리 구조), 외부 크레이트/표준 라이브러리 무시. - HYG-01 추가 룰 (언어별):
- C#
async void메서드 — violation / medium. (이벤트 핸들러 시그니처(object sender, EventArgs)는 info 로 강등) - C#
.Result/.Wait()호출 — warning / medium (데드락 위험). - Rust
.unwrap()/.expect(— 파일당 발생 횟수가 5 초과 시 한 건의 warning 요약 (값=카운트), 그 외는 info. - RES 추가 룰 (Rust):
mem::forget(/Box::leak(— warning / medium.unsafe {블록 — info 각 1 건, 파일당 > 3 이면 한 건의 warning 요약 (값=카운트).- 공통: confidence medium 은 finding 에 노출하되 부채는 100% 산입한다. confidence low 만 SQALE 의 50% 부채 가중 (docs/03) 으로 처리 — 임계값/가중치 산식 변경 없음.
v1.1.1 (2026-06-11)
PATCH — 오탐 제거 (검출 정확화). 산식·임계값·가중치 변경 없음. 실프로젝트 3 종 (대형 TS 모노레포 포함) 캘리브레이션 결과 반영.
- DUP-01: (a) import/모듈 헤더 라인을 토큰 스트림에서 제외 — 정규화 후 동일해지는 import 보일러플레이트가 클론으로 잡히던 오탐 제거. (b) 시프트된 해시 윈도가 같은 중복 영역을 여러 클래스로 중복 보고하던 문제를 라인 커버리지 50% 기준 greedy dedup 으로 억제 (동일 finding_id 중복 행 버그 동시 해소).
- SEC-01(b): 공백을 포함한 문자열 값 제외 (실제 자격증명에는 공백이 없음 — 영문 UI 문자열의 엔트로피 오탐 제거), 복수형 "tokens" 포함 식별자 제외 (LLM 토큰 카운트 문맥).
- 리포트/콘솔: 위반이 있는데 카테고리 점수가 ~100 인 경우 (SQALE 희석) 설명 각주 추가 — 점수 자체는 불변.
v1.1.0 (2026-06-10)
MINOR — 기존 메트릭에 언어 규칙 추가 (11-metrics-versioning.md §2). 임계값·가중치·산식 변경 없음.
- SIZE-02/03, CPLX-01/02/03: TypeScript/JavaScript/Python 규칙 추가 —
internal/lang경량 렉서 프론트엔드 (퍼지 파싱, lizard 방식) 로 함수 단위 측정. 임계값은 Go 와 동일하게 적용하되, 퍼지 파싱이므로 해당 언어 판정의 confidence 는 전부 medium (Go 경로는 기존대로 high, CPLX-02 만 medium). - ARCH-01/03: TS/JS 파일 단위 그래프 (상대 import 만 해석,
/index.*규칙 포함) 와 Python 패키지 단위 그래프 추가. Go 패키지 그래프는 변경 없음. 해석 실패 import 는 외부로 처리 (가짜 사이클 방지). - tree-sitter WASM 프론트엔드는 emscripten 툴체인 부재로 이연 — 08-roadmap.md 리스크 레지스터의 폴백 경로 (자체 렉서) 채택. 05-language-support.md 참고.
v1.0.0 (2026-06-10)
최초 스펙. 02-metrics-catalog.md 의 29 개 메트릭 정의 전체를 수록.
- 카테고리 가중치: ARCH 0.22, CPLX 0.20, SEC 0.20, DUP 0.15, SIZE 0.10, RES 0.08, HYG 0.05
- SQALE 상수: cost/line 3.6 분, TDR_max 0.20, 파일 cap 30%
- 등급 컷: A≥90, B≥80, C≥65, D≥50
- 하드 캡: SEC critical → 최대 C, ARCH-01 SCC≥5 → 최대 B
- 구현 상태: CPLX-04/05, ARCH-02, DUP-02, HYG-04/05 는 정의만 존재 (
Implemented: false) — 측정되지 않으며 점수에 영향 없음