09. 샘플 출력 (예상 결과)
실제 산출물 계약을 설명하는 가상 샘플이다. 바이브코딩 프로젝트 shopmate(TypeScript + Python, 전체 70파일/5,157 CLOC, 이 중 production 62파일/4,820 CLOC)를 스캔했다고 가정한다.
수치는 포맷 시연용 예시다(M3 캘리브레이션 전 기본 임계값 기준). 단, 점수 계산 사슬(debt → TDR → 카테고리 점수 → 가중 합 → 등급)은 03-scoring-model.md의 공식과 정확히 일치하도록 작성했다 — 산출물 간 일관성이 이 문서의 검증 포인트다.
1. 콘솔 출력
$ jam scan ./shopmate
JAM Lite v0.46.0 — scanning ./shopmate
files: 70 · 5,157 CLOC · production: 62 files / 4,820 CLOC · excluded: 214 (node_modules)
████████████████████████████████ 62/62 (1.8s)
┌─────────────────────────────────────────────────────────────┐
│ JAM Lite Score: 19 / 100 (Grade F) │
├──────────────┬───────┬───────────────────────────────────────┤
│ Architecture │ 10 │ 순환 참조 3건 (최대 SCC 5개 파일) │
│ Complexity │ 36 │ CCN>15 함수 9개, 인지복잡도>25 6개 │
│ Security │ 0 │ ⚠ 하드코딩 시크릿 2건, TLS 검증 해제 1건│
│ Duplication │ 4 │ 중복률 14.8% (클론 37쌍) │
│ Size │ 26 │ 1,843 CLOC 파일 1개 (전체의 38%) │
│ Resource │ 48 │ 자원 해제 누락 7건 │
│ Hygiene │ 60 │ 삼킨 예외 18건, TODO 23건 │
└──────────────┴───────┴───────────────────────────────────────┘
critical 3 · violation 96 · warning 86 · info 54 · score-excluded 8 (총 247건)
※ SEC critical 존재 → 등급 상한 C 적용 대상 (현재 점수가 F라 영향 없음)
→ jam-report.md
→ jam-detail.csv (247 rows)
→ jam-run.json (policy/scope/integrity manifest)
2. jam-report.md (생성 파일 전문 예시)
# JAM Lite Report — shopmate
> 스캔: 2026-06-10 14:02:11 (+09:00) · jam v0.46.0 · metrics v14.5.0 · 대상: /home/dev/shopmate
> 파일 70개 · 전체 5,157 CLOC · production 62개/4,820 CLOC · 언어: TypeScript 72%, Python 21%, 기타 7%
> 제외: 214개 (node_modules 198, 생성 파일 9, 비소스 7) — 부록 B 참조
> 측정 정책: `engineering/portfolio` v3 (`<policy-hash>`) · 무결성: **complete** · 비교 키: `<comparison-key>`
## JAM Lite Score: 19 / 100 (Grade F)
구조적 부채가 매우 큽니다. 기능 추가 전 재설계와 보안 수정이 필요합니다.
**등급 캡**: SEC critical 3건 → 등급 상한 C 적용 대상이나, 가중 점수(19)가 이미 F이므로 영향 없음.
| 카테고리 | 점수 | 가중치 | 기여 | 핵심 문제 |
|---|---:|---:|---:|---|
| Architecture | 10 | 0.22 | 2.2 | 순환 참조 3건 (최대 SCC 5개 파일) |
| Complexity | 36 | 0.20 | 7.2 | CCN>15 함수 9개, 최대 CCN 34 |
| Security | 0 | 0.20 | 0.0 | 시크릿 2건, TLS 해제 1건, SQL 결합 8건 |
| Duplication | 4 | 0.15 | 0.6 | 중복률 14.8% (임계 10%) |
| Size | 26 | 0.10 | 2.6 | checkout.ts 1,843 CLOC |
| Resource | 48 | 0.08 | 3.8 | close/with 누락 7건 |
| Hygiene | 60 | 0.05 | 3.0 | 삼킨 예외 18건 |
| **합계** | | **1.00** | **19.4 → 19** | |
## Top Findings (수정 효과 큰 순)
1. **[SIZE-01·critical]** `src/services/checkout.ts:1` — 1,843 CLOC (전체 코드의 38%가 한 파일). 결제·재고·알림·할인 로직이 모두 이 파일에 있음 → 책임 분리 필요 *(debt 480분)*
2. **[ARCH-01·violation]** 서비스 계층 순환 — `src/routes/order.ts:4` → `src/services/billing.ts:9` → `src/services/order.ts:6` → `src/services/inventory.ts:3` → `src/services/checkout.ts:12` → (다시 routes/order.ts) — SCC 5파일 *(debt 300분)*
3. **[SEC-01·critical]** `src/config/database.ts:12` — DB 비밀번호 하드코딩 (고엔트로피 문자열, `password` 할당) *(debt 120분)*
4. **[SEC-01·critical]** `scripts/deploy.py:8` — AWS Access Key 패턴(`AKIA…`) 하드코딩 *(debt 120분)*
5. **[SEC-03·critical]** `src/utils/http.ts:34` — `rejectUnauthorized: false` 로 TLS 인증서 검증 비활성화 *(debt 120분)*
6. **[CPLX-01·critical]** `src/services/checkout.ts:41` — `processCheckout` CCN 34 (임계 30), 인지복잡도 47 *(debt 120분)*
7. **[DUP-01·violation]** `src/jobs/sync.ts:40` ↔ `src/jobs/import.ts:22` ↔ `src/jobs/export.ts:75` — 57라인 블록이 3곳에 중복 *(debt 135분)*
8. **[ARCH-01·violation]** `src/utils/format.ts:2` ↔ `src/utils/helpers.ts:5` ↔ `src/utils/date.ts:3` — 유틸 3파일 순환 *(debt 180분)*
9. **[SEC-02·critical]** `src/repositories/product.repo.ts:88` — 사용자 입력이 포함된 문자열 결합 SQL을 `db.query()`에 직접 전달 *(debt 60분)*
10. **[RES-01·violation]** `scripts/migrate.py:23` — `open()` 결과가 `with` 없이 사용되고 `close()` 호출 없음 *(debt 30분)*
## 카테고리별 상세
### Architecture — 10/100 (debt 1,452분 / TDR 9.0%)
**순환 의존 3건** (ARCH-01):
- SCC#1 (5파일): `routes/order.ts` → `services/billing.ts` → `services/order.ts` → `services/inventory.ts` → `services/checkout.ts` → `routes/order.ts`
- 권장: 서비스 간 직접 import 대신 인터페이스 분리 또는 이벤트/콜백 역전
- SCC#2 (3파일): `utils/format.ts` → `utils/helpers.ts` → `utils/date.ts` → `utils/format.ts`
- SCC#3 (2파일): `models/user.ts` ↔ `models/session.ts`
**과결합 모듈** (ARCH-03):
- `src/utils/helpers.ts` — Ce(원심 결합) 29: 프로젝트의 거의 모든 모듈을 import. "만능 유틸" 안티패턴
- `src/services/checkout.ts` — Ce 24
- SDP 위반 에지 4건: 안정 모듈(`models/`)이 불안정 모듈(`routes/`)을 역참조 — 상세는 detail.csv ARCH-03 행 참조
### Complexity — 36/100 (debt 1,033분 / TDR 6.4%)
| 함수 | 위치 | CCN | 인지복잡도 | 중첩 |
|---|---|---:|---:|---:|
| processCheckout | src/services/checkout.ts:41 | 34 | 47 | 7 |
| applyDiscountRules | src/services/checkout.ts:412 | 23 | 31 | 5 |
| syncInventory | src/jobs/sync.ts:101 | 19 | 26 | 5 |
| validateOrder | src/services/order.ts:55 | 17 | 18 | 4 |
| …외 5건 (CCN 15 초과) | | | | |
동일 함수에서 CCN·인지복잡도 동시 위반 시 큰 쪽만 debt 산입(이중 감점 방지) — 6개 함수에 적용됨.
### Security — 0/100 (debt 1,906분 / TDR 11.8%)
- **시크릿 2건 (critical)**: database.ts:12, deploy.py:8 — 즉시 폐기·로테이션 권장
- **TLS 검증 비활성화 1건 (critical)**: http.ts:34
- **SQL 문자열 결합 8건**: product.repo.ts(3), order.repo.ts(4), user.repo.ts(1) — 파라미터 바인딩으로 교체
- **취약 해시 2건**: user.service.ts:77 (MD5로 비밀번호 해싱 — CWE-327)
- **민감 정보 로깅 5건**: auth.ts:23 등 — `console.log(token)` 류
- 경고 25건: 보안 문맥의 `Math.random()` 등 — detail.csv 참조
### Duplication — 4/100 (debt 1,549분 / TDR 9.6% · 중복률 14.8%)
클론 37쌍. 최대 클러스터는 jobs/ 디렉터리의 동기화 루틴(57라인 × 3곳).
패턴: API 핸들러의 검증-조회-응답 보일러플레이트가 라우트마다 복제됨 (`routes/*.ts`에서 21쌍).
### Size — 26/100 (debt 1,284분 / TDR 7.4%)
- `src/services/checkout.ts` — 1,843 CLOC (critical). God File 판정(SIZE-04 동시 해당: 선언 38개, fan-in 상위 2%)
- `src/routes/api.ts` — 743 CLOC (warning)
- 함수 길이 위반 6건 (120라인 초과), 매개변수 8개 초과 3건
### Resource — 48/100 (debt 189분 / TDR 5.2%)
- Python 파일/커넥션 해제 누락 7건: migrate.py:23, seed.py:41 등
- TypeScript의 자원 관련 휴리스틱 finding은 현재 RES 지원 언어 밖이므로 감사 출력에는 남지만 RES debt에는 산입하지 않는다.
### Hygiene — 60/100 (debt 646분 / TDR 4.0%)
- 삼킨 예외 18건: 빈 catch 11(ts), `except: pass` 4(py), `_ = err` 류 3
- 죽은 코드 7건: 미참조 비공개 함수 (confidence: medium)
- TODO/FIXME 23건 (4.8건/KLOC — 경고 수준)
## 파일 핫스팟 (debt 상위)
| 파일 | debt(분) | 주요 메트릭 |
|---|---:|---|
| src/services/checkout.ts | 1,118 | SIZE-01, SIZE-04, CPLX-01×2, ARCH-01, DUP-01×4 |
| src/jobs/sync.ts | 412 | DUP-01×3, CPLX-01, RES-02 |
| src/repositories/order.repo.ts | 305 | SEC-02×4, DUP-01×2 |
| src/utils/helpers.ts | 268 | ARCH-01, ARCH-03, DUP-01×2 |
| scripts/deploy.py | 196 | SEC-01, RES-01, HYG-01×2 |
| …외 상위 10개까지 | | |
※ debt는 score-eligible finding의 remediation cost를 가산한다. 한 파일에 집중됐다는 이유로 할인하지 않는다.
## 부록 A. 점수 계산 근거
카테고리별 dev cost = eligible production CLOC × 3.6분. core 언어(TS/Python)는 4,482 CLOC, SIZE는 `other` production까지 4,820 CLOC, RES는 구현된 Python 1,012 CLOC가 eligible이다.
| 카테고리 | coverage | eligible/production CLOC | findings | dev cost(분) | debt_counted(분) | TDR | 점수 |
|---|---:|---:|---:|---:|---:|---:|---:|
| ARCH | 93.0% | 4,482/4,820 | 14 | 16,135.2 | 1,452 | 0.0900 | 10 |
| CPLX | 93.0% | 4,482/4,820 | 41 | 16,135.2 | 1,033 | 0.0640 | 36 |
| SEC | 93.0% | 4,482/4,820 | 52 | 16,135.2 | 1,906 | 0.1181 | 0 |
| DUP | 93.0% | 4,482/4,820 | 37 | 16,135.2 | 1,549 | 0.0960 | 4 |
| SIZE | 100.0% | 4,820/4,820 | 23 | 17,352 | 1,284 | 0.0740 | 26 |
| RES | 21.0% | 1,012/4,820 | 18 | 3,643.2 | 189 | 0.0519 | 48 |
| HYG | 93.0% | 4,482/4,820 | 54 | 16,135.2 | 646 | 0.0400 | 60 |
| **합계** | | | **239** | | **8,059** | | **가중 합 19.44 → 19 (F)** |
## 부록 B. 스캔 범위
- 제외 디렉터리: `node_modules/` (198파일, gitignore), `dist/` (gitignore)
- 생성 파일 제외 9건: `src/api/client.gen.ts` 외 — "Code generated" 헤더 감지
- 비UTF-8 스킵 1건: `docs/old-spec.txt` (EUC-KR 추정)
- 파스 실패 0건
- 점수 제외 finding 8건: test 4, documentation 1, configuration 1, unsupported_language 2 (`jam-detail.csv`의 `score_exclusion` 참조)
## 부록 C. 적용된 임계값
| 메트릭 | warning | violation | critical | 근거 |
|---|---:|---:|---:|---|
| SIZE-01 (파일 CLOC) | 500 | 1,000 | 2,000 | Basili 1984 |
| CPLX-01 (CCN) | 10 | 15 | 30 | McCabe 1976 |
| CPLX-02 (인지복잡도) | 15 | 25 | — | Campbell 2018 |
| DUP-01 (중복률) | 5% | 10% | 20% | Juergens 2009 |
| … | | | | `jam explain <ID>` 참조 |
3. jam-detail.csv (247행 중 대표 23행 발췌)
06-output-spec.md §1.2의 스키마. 실제 파일은 category, metric_id, file, line 순 정렬로 전체 finding을 담는다.
finding_id,category,metric_id,metric_name,metric_version,severity,confidence,file,line,end_line,column,symbol,value,threshold,message,related,debt_minutes,debt_counted,rule_ref,suppressed,suppression_source,suppression_reason,suppression_owner,suppression_ticket,suppression_expires,score_exclusion
ARCH-01-2e81d04a,ARCH,ARCH-01,Dependency Cycle,1,violation,high,src/routes/order.ts,4,4,1,routes/order,5,0,"순환 의존 SCC#1 (5파일): routes/order.ts → services/billing.ts → services/order.ts → services/inventory.ts → services/checkout.ts → routes/order.ts","src/services/billing.ts:9;src/services/order.ts:6;src/services/inventory.ts:3;src/services/checkout.ts:12",300,300,Lakos1996,false,,,,,,
ARCH-01-5cb37f19,ARCH,ARCH-01,Dependency Cycle,1,violation,high,src/utils/format.ts,2,2,1,utils/format,3,0,"순환 의존 SCC#2 (3파일): utils/format.ts → utils/helpers.ts → utils/date.ts → utils/format.ts","src/utils/helpers.ts:5;src/utils/date.ts:3",180,180,Lakos1996,false,,,,,,
ARCH-01-91da6c02,ARCH,ARCH-01,Dependency Cycle,1,violation,high,src/models/user.ts,7,7,1,models/user,2,0,"순환 의존 SCC#3 (2파일): models/user.ts ↔ models/session.ts","src/models/session.ts:2",120,120,Lakos1996,false,,,,,,
ARCH-03-c4f00b21,ARCH,ARCH-03,Efferent Coupling,1,violation,high,src/utils/helpers.ts,1,1,1,utils/helpers,29,25,"원심 결합(Ce) 29 — 만능 유틸 모듈. 책임별 분리 권장",,30,30,Martin1994,false,,,,,,
ARCH-03-880fe1d7,ARCH,ARCH-03,Stable-Dependencies Violation,1,warning,medium,src/models/order.ts,5,5,1,models/order,0.18,0,"안정 모듈(I=0.18)이 불안정 모듈 routes/webhook.ts(I=0.92)에 의존 — SDP 위반","src/routes/webhook.ts:1",10,10,Martin1994,false,,,,,,
SIZE-01-7b3a9e55,SIZE,SIZE-01,File Size,1,critical,high,src/services/checkout.ts,1,1843,1,,1843,1000,"파일 1,843 CLOC — 전체 코드의 38%. 결제·재고·알림·할인 책임 혼재",,480,480,Basili1984,false,,,,,,
SIZE-01-d20c1188,SIZE,SIZE-01,File Size,1,warning,high,src/routes/api.ts,1,743,1,,743,500,"파일 743 CLOC (경고 임계 500)",,10,10,Basili1984,false,,,,,,
SIZE-04-3fe6a0c9,SIZE,SIZE-04,God File,1,violation,medium,src/services/checkout.ts,1,1,1,,38,30,"선언 38개 + fan-in 상위 2% — 책임 집중(God File)",,60,30,Lanza2006,false,,,,,,
CPLX-01-a3f9c2d1,CPLX,CPLX-01,Cyclomatic Complexity,1,critical,high,src/services/checkout.ts,41,238,1,processCheckout,34,30,"함수 'processCheckout'의 순환 복잡도 34 (critical 임계 30)",,120,120,McCabe1976,false,,,,,,
CPLX-02-66b1e8a0,CPLX,CPLX-02,Cognitive Complexity,1,info,high,src/services/checkout.ts,41,238,1,processCheckout,47,25,"인지 복잡도 47 — 동일 함수의 CPLX-01이 더 크므로 info로 강등(이중 감점 방지)",,30,0,Campbell2018,false,,,,,,
CPLX-01-be55d317,CPLX,CPLX-01,Cyclomatic Complexity,1,violation,high,src/jobs/sync.ts,101,177,1,syncInventory,19,15,"함수 'syncInventory'의 순환 복잡도 19 (임계 15)",,30,30,McCabe1976,false,,,,,,
CPLX-03-1d9f3c72,CPLX,CPLX-03,Nesting Depth,1,warning,high,src/services/checkout.ts,156,171,9,processCheckout,7,6,"중첩 깊이 7 (if > for > if > try > if > for > if)",,10,10,Hindle2008,false,,,,,,
DUP-01-9c2d10b3,DUP,DUP-01,Duplicated Block,2,violation,high,src/jobs/sync.ts,40,96,1,,57,6,"57라인 블록이 3개 위치에 중복 (Type-2: 식별자만 상이)","src/jobs/import.ts:22;src/jobs/export.ts:75",135,135,Baker1995,false,,,,,,
DUP-01-44a7f6ce,DUP,DUP-01,Duplicated Block,2,violation,high,src/routes/product.ts,18,42,1,,25,6,"검증-조회-응답 보일러플레이트 중복","src/routes/user.ts:21;src/routes/cart.ts:15",45,45,Baker1995,false,,,,,,
SEC-01-f01c44aa,SEC,SEC-01,Hardcoded Secret,1,critical,high,src/config/database.ts,12,12,22,DB_PASSWORD,4.9,4.5,"고엔트로피 문자열(entropy 4.9)이 'DB_PASSWORD'에 할당됨 — 키 로테이션 권장",,120,120,CWE-798,false,,,,,,
SEC-01-0a92bd64,SEC,SEC-01,Hardcoded Secret,1,critical,high,scripts/deploy.py,8,8,15,AWS_KEY,0,0,"AWS Access Key 패턴(AKIA…) 검출",,120,120,CWE-798,false,,,,,,
SEC-03-e7c2519b,SEC,SEC-03,TLS Verification Disabled,1,critical,high,src/utils/http.ts,34,34,5,,0,0,"rejectUnauthorized: false — TLS 인증서 검증 비활성화",,120,120,CWE-295,false,,,,,,
SEC-02-2b6e88d0,SEC,SEC-02,SQL String Concatenation,1,critical,high,src/repositories/product.repo.ts,88,88,12,findByCategory,0,0,"사용자 입력 포함 문자열 결합 SQL이 db.query()에 직접 전달됨 — 파라미터 바인딩 사용",,60,60,CWE-89,false,,,,,,
SEC-03-77d1340f,SEC,SEC-03,Weak Hash,1,violation,high,src/services/user.service.ts,77,77,18,hashPassword,0,0,"MD5로 비밀번호 해싱 — bcrypt/argon2 권장",,60,60,CWE-327,false,,,,,,
RES-01-c81b52e6,RES,RES-01,Resource Leak,1,violation,high,scripts/migrate.py,23,23,8,run_migration,0,0,"open() 결과가 with 블록 외부에서 사용되고 close() 없음",,30,30,Hovemeyer2004,false,,,,,,
RES-02-39f0aa17,RES,RES-02,Unbounded Concurrency,1,warning,low,src/jobs/sync.ts,130,130,5,syncAll,0,0,"한도 없는 일괄 비동기 발사(orders.map(processAsync)) — 워커풀/세마포어 부재 (confidence low: debt 50% 산입)",,10,5,—,false,,,,,,
HYG-01-6d44e09f,HYG,HYG-01,Swallowed Exception,1,violation,high,src/middleware/auth.ts,67,69,11,verifyToken,0,0,"빈 catch 블록 — 토큰 검증 실패가 무시됨",,30,30,Yuan2014,false,,,,,,
SEC-01-ea17c944,SEC,SEC-01,Hardcoded Secret,1,critical,high,tests/fixtures/payment.test.ts,12,12,1,,4.8,4.5,"테스트 fixture 시크릿",,120,0,CWE-798,false,,,,,,test
(이하 225행 생략 — 실제 파일에는 info 포함 전수 기록)
CSV에서 확인되어야 할 일관성 포인트
| 검증 항목 | 예시 |
|---|---|
| 이중 감점 방지 | CPLX-02-66b1e8a0: severity가 info로 강등되고 debt_counted=0, 사유가 message에 명시 |
| confidence 보정 | RES-02-39f0aa17: low → debt_minutes=10, debt_counted=5 |
| 점수 범위 제외 | SEC-01-ea17c944: 원 심각도·raw debt는 보존, debt_counted=0, score_exclusion=test |
| 사이클 경로 재현 | ARCH-01 행의 related에 사이클 전체 경로가 파일:라인으로 나열 |
| 클론 상대편 | DUP-01 행의 related에 중복 위치 전부 기록 |
| 점수 역산 | 카테고리별 debt_counted 합 = 부록 A의 debt 열과 일치 |
4. jam-result.json (--json 옵션 시)
{
"version": "3",
"metricSet": "jam-lite",
"tool": { "name": "jam", "version": "v0.46.0" },
"metricsSpec": { "version": "14.5.0" },
"scannedAt": "2026-06-10T14:02:11+09:00",
"target": {
"path": "/home/dev/shopmate",
"files": 70,
"cloc": 5157,
"productionFiles": 62,
"productionCloc": 4820,
"languages": { "typescript": 0.72, "python": 0.21, "other": 0.07 }
},
"score": {
"status": "assessed",
"total": 19,
"grade": "F",
"capNote": "SEC critical 3건 → 상한 C 대상이나 가중 점수가 이미 F",
"notAssessed": [],
"categories": {
"ARCH": { "score": 10, "debtMinutes": 1452, "tdr": 0.0900, "highRiskFiles": 6, "highRiskShare": 0.1111, "productionCloc": 4820, "eligibleCloc": 4482, "productionFiles": 62, "eligibleFiles": 54, "coverage": 0.9299, "devCostMinutes": 16135.2 },
"CPLX": { "score": 36, "debtMinutes": 1033, "tdr": 0.0640, "highRiskFiles": 4, "highRiskShare": 0.0741, "productionCloc": 4820, "eligibleCloc": 4482, "productionFiles": 62, "eligibleFiles": 54, "coverage": 0.9299, "devCostMinutes": 16135.2 },
"SEC": { "score": 0, "debtMinutes": 1906, "tdr": 0.1181, "highRiskFiles": 5, "highRiskShare": 0.0926, "productionCloc": 4820, "eligibleCloc": 4482, "productionFiles": 62, "eligibleFiles": 54, "coverage": 0.9299, "devCostMinutes": 16135.2 },
"DUP": { "score": 4, "debtMinutes": 1549, "tdr": 0.0960, "highRiskFiles": 7, "highRiskShare": 0.1296, "productionCloc": 4820, "eligibleCloc": 4482, "productionFiles": 62, "eligibleFiles": 54, "coverage": 0.9299, "devCostMinutes": 16135.2 },
"SIZE": { "score": 26, "debtMinutes": 1284, "tdr": 0.0740, "highRiskFiles": 3, "highRiskShare": 0.0484, "productionCloc": 4820, "eligibleCloc": 4820, "productionFiles": 62, "eligibleFiles": 62, "coverage": 1.0, "devCostMinutes": 17352 },
"RES": { "score": 48, "debtMinutes": 189, "tdr": 0.0519, "highRiskFiles": 2, "highRiskShare": 0.1538, "productionCloc": 4820, "eligibleCloc": 1012, "productionFiles": 62, "eligibleFiles": 13, "coverage": 0.21, "devCostMinutes": 3643.2 },
"HYG": { "score": 60, "debtMinutes": 646, "tdr": 0.0400, "highRiskFiles": 3, "highRiskShare": 0.0556, "productionCloc": 4820, "eligibleCloc": 4482, "productionFiles": 62, "eligibleFiles": 54, "coverage": 0.9299, "devCostMinutes": 16135.2 }
},
"devCostMinutes": 17352
},
"findingCounts": { "critical": 3, "violation": 96, "warning": 86, "info": 54, "suppressed": 0, "excluded": 8 },
"policy": { "id": "engineering/portfolio", "version": "3", "hash": "<sha256>" },
"configuration": { "hash": "<sha256>" },
"scope": { "metricSet": "jam-lite", "categories": ["SIZE", "CPLX", "ARCH", "DUP", "SEC", "RES", "HYG"], "includeGenerated": false, "excludes": [] },
"integrity": { "status": "complete", "reasons": [], "skippedFiles": [], "parseFailures": [], "analyzerErrors": [], "configWarnings": [], "suppressionIssues": [], "notAssessed": [] },
"comparisonKey": "<sha256>"
}
5. CI 게이트 사용 예
$ jam scan ./shopmate --fail-under 70 --quiet
JAM Lite Score: 19/100 (F) — fail-under 70 미달
$ echo $?
1
6. 이 샘플이 고정하는 계약
이 문서는 구현 시 golden test의 출발점이 된다:
- 콘솔 요약 박스 ↔ report.md 카테고리 표 ↔ JSON
categories의 수치 동일성 - report.md 부록 A의 debt 합계 = CSV
debt_counted카테고리별 합 - Top Findings 정렬 =
debt_counted내림차순 (동률 시 severity 순) - 모든 위치 표기
path:line형식 + CSVrelated로 다중 위치 표현 - 점수 공식:
100 × (1 − TDR/0.10)와 가중 합Σ(score × weight) = 19.44 → 19재현 가능