leerness 1.9.26 → 1.9.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +31 -0
- package/README.md +86 -66
- package/bin/harness.js +79 -10
- package/package.json +1 -1
- package/scripts/e2e.js +53 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,36 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.9.27 — 2026-05-15
|
|
4
|
+
|
|
5
|
+
**낙관적 표시 방지 강화 — URL/메서드 단위 매핑 + 10 카테고리 + 신뢰도 점수**.
|
|
6
|
+
|
|
7
|
+
1.9.26의 sub-agent B 검증에서 발견한 false negative (T-9001 "POST /users" 케이스, 같은 프로젝트에 다른 목적의 http.request 있으면 통과)를 정확히 해결.
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- **URL/메서드 단위 매핑** (1.9.27 핵심): evidence에서 `POST /users` 같은 구체 경로 추출 → 코드에서 같은 경로 호출 검사. 1.9.26의 "fetch 키워드 존재" 약한 신호 → "실제 경로 일치" 강한 신호.
|
|
12
|
+
- **카탈로그 확장 5→10 카테고리**: FileIO / Queue / Cache / Notify(Slack/Discord) / Storage(S3/GCS/Azure) 신규.
|
|
13
|
+
- **신뢰도 점수** (0.0~1.0): high (1.0 가중치) + medium (0.5 가중치) 의심을 evidence 주장 수로 나눠 신뢰도 산출. < 0.5 = ⚠ 낮음, < 0.9 = ⓘ 보통, ≥ 0.9 = ✓ 높음.
|
|
14
|
+
|
|
15
|
+
### Why
|
|
16
|
+
1.9.26 sub-agent B 검증에서 발견:
|
|
17
|
+
- T-9001 evidence "POST /users API 호출 완료" + 같은 프로젝트에 다른 목적의 `http.request({path: '/api/tags'})` 존재 → 1.9.26은 "API 카테고리 통과"로 false negative
|
|
18
|
+
- 1.9.27 URL 매핑: "POST /users" 추출 후 코드에서 `/users` 검색 → 미발견 → 의심 감지 (MED severity)
|
|
19
|
+
|
|
20
|
+
### Limitations (1.9.28 후보)
|
|
21
|
+
- AST 분석 여전히 미구현 — 단순 substring 매칭의 한계
|
|
22
|
+
- URL 매핑이 path만 — query string, header 검증 없음
|
|
23
|
+
- 패턴 카탈로그 10종으로 확장됐지만 도메인 특화 패턴 (GraphQL, gRPC) 미커버
|
|
24
|
+
|
|
25
|
+
### Migration
|
|
26
|
+
```bash
|
|
27
|
+
npx leerness@latest update . --yes
|
|
28
|
+
|
|
29
|
+
# 강화된 명령 사용
|
|
30
|
+
leerness optimism-check T-0001 --path . --json # 신뢰도 점수 포함
|
|
31
|
+
leerness verify-claim T-0001 --strict-claims # 통합 검사
|
|
32
|
+
```
|
|
33
|
+
|
|
3
34
|
## 1.9.26 — 2026-05-15
|
|
4
35
|
|
|
5
36
|
**낙관적 표시 방지 — `optimism-check <T-ID>` + `verify-claim --strict-claims`** (사용자 명시 요구사항).
|
package/README.md
CHANGED
|
@@ -2,26 +2,24 @@
|
|
|
2
2
|
|
|
3
3
|
> 한국어 우선 AI 개발 하네스. 멀티 에이전트 오케스트레이션 · 자동 검수 · 워크스페이스 가시성 · Ollama opt-in 통합.
|
|
4
4
|
|
|
5
|
-
[](https://www.npmjs.com/package/leerness) [](https://www.npmjs.com/package/leerness) []() []() []()
|
|
6
6
|
|
|
7
7
|
## ⚙️ 설치 (Install)
|
|
8
8
|
|
|
9
|
-
> ⚠️ **leerness는 CLI 도구입니다.** `npm i leerness
|
|
9
|
+
> ⚠️ **leerness는 CLI 도구입니다.** `npm i leerness`(로컬)만으로는 `leerness` 명령이 PATH에 없어 실패할 수 있습니다. 아래 셋 중 하나를 사용하세요:
|
|
10
10
|
|
|
11
11
|
```bash
|
|
12
12
|
# ✅ 1) 추천 — 설치 없이 즉시 실행 (npx 자동 캐시)
|
|
13
13
|
npx leerness@latest init . --language ko --skills recommended
|
|
14
14
|
|
|
15
15
|
# ✅ 2) 전역 설치 (한 번 설치 후 어디서나 leerness 명령)
|
|
16
|
-
npm i -g leerness
|
|
17
|
-
leerness --version
|
|
16
|
+
npm i -g leerness && leerness --version
|
|
18
17
|
|
|
19
|
-
# ✅ 3) 로컬 dev dependency + npx
|
|
20
|
-
npm i --save-dev leerness
|
|
21
|
-
npx leerness handoff .
|
|
18
|
+
# ✅ 3) 로컬 dev dependency + npx 실행
|
|
19
|
+
npm i --save-dev leerness && npx leerness handoff .
|
|
22
20
|
```
|
|
23
21
|
|
|
24
|
-
> npmjs.com
|
|
22
|
+
> npmjs.com의 `npm i leerness`는 라이브러리 import용. CLI 명령(`leerness ...`) 직접 호출은 위 3가지 중 하나 필요.
|
|
25
23
|
|
|
26
24
|
---
|
|
27
25
|
|
|
@@ -31,21 +29,22 @@ npx leerness handoff .
|
|
|
31
29
|
- 다음 세션이 컨텍스트를 잃는 문제 → handoff/current-state 3채널 자동 생성
|
|
32
30
|
- 멀티 에이전트 분담 시 누가 뭘 했는지 안 보임 → `handoff --all-apps --since 1h`
|
|
33
31
|
- LLM 컨텍스트 비용 → `--compact` 모드로 4KB → 500자
|
|
32
|
+
- AI가 "API 호출 완료"라 보고했지만 코드에 호출 흔적이 없는 낙관적 표시 → `optimism-check`로 자동 감지 (1.9.26/27)
|
|
34
33
|
|
|
35
34
|
---
|
|
36
35
|
|
|
37
36
|
## 🚀 60초 시작
|
|
38
37
|
|
|
39
38
|
```bash
|
|
40
|
-
# 1) 신규 프로젝트 (
|
|
39
|
+
# 1) 신규 프로젝트 (설치 불필요)
|
|
41
40
|
npx leerness@latest init . --language ko --skills recommended
|
|
42
41
|
|
|
43
|
-
# 2) 기존
|
|
42
|
+
# 2) 기존 프로젝트 자동 업그레이드
|
|
44
43
|
npx leerness@latest update . --yes
|
|
45
44
|
|
|
46
45
|
# 3) 매일 사용
|
|
47
|
-
npx leerness handoff .
|
|
48
|
-
npx leerness audit .
|
|
46
|
+
npx leerness handoff . # 컨텍스트 적재
|
|
47
|
+
npx leerness audit . # 일관성 감사
|
|
49
48
|
npx leerness verify-claim T-0001 --run-tests # evidence 자동 검증
|
|
50
49
|
```
|
|
51
50
|
|
|
@@ -63,6 +62,7 @@ npx leerness verify-claim T-0001 --run-tests # evidence 자동 검증
|
|
|
63
62
|
| 워크스페이스 가시성 (1 vs 64 명령) | 98/100 | 0/100 | **+98** |
|
|
64
63
|
| 버그 자동 감지 (158 신호) | 100/100 | 0/100 | **+100** |
|
|
65
64
|
| 컨텍스트 유지 (3채널) | 100/100 | 0/100 | **+100** |
|
|
65
|
+
| 낙관적 표시 방지 | 1.9.26+ verify-claim/optimism-check | N/A | 95+/100 |
|
|
66
66
|
| **종합** | **503/600** | **3/600** | **+500 (151×)** |
|
|
67
67
|
|
|
68
68
|
로컬 LLM 실측 (Ollama deepseek-coder-v2:16b):
|
|
@@ -88,6 +88,9 @@ leerness verify-code . --bench # test + lint + bench 일괄 실행
|
|
|
88
88
|
leerness audit . # 일관성/계획↔진행 감사
|
|
89
89
|
leerness lazy detect . # 거짓 완료 자동 감지
|
|
90
90
|
leerness gate . # verify + audit + scan + encoding + lazy 일괄
|
|
91
|
+
leerness optimism-check T-0001 # 1.9.26/27 낙관적 표시 자동 감지
|
|
92
|
+
leerness verify-claim T-0001 --strict-claims # 1.9.26 verify-claim에 낙관적 검사 통합
|
|
93
|
+
leerness deps <capability> --run-tests # 1.9.24 영향 추적 + 자동 회귀
|
|
91
94
|
```
|
|
92
95
|
|
|
93
96
|
### 워크스페이스 (멀티 프로젝트)
|
|
@@ -98,6 +101,9 @@ leerness reuse-map --all-apps --strict-elements # 함수명 fuzzy 중복
|
|
|
98
101
|
leerness handoff --all-apps --since 24h # 최근 변경 워크스페이스 뷰
|
|
99
102
|
leerness brainstorm "키워드" --all-apps # 누적 데이터 검색
|
|
100
103
|
leerness insights --all-apps # 통계 + 안정성 평가
|
|
104
|
+
leerness memory search "키" --include-code # 1.9.25 소스 코드 본문도 검색
|
|
105
|
+
leerness brainstorm "주제" --include-code # 1.9.25 코드 hits 포함
|
|
106
|
+
leerness register-pending "<요청>" --agent X # 1.9.25 다중 세션 즉시 신호
|
|
101
107
|
```
|
|
102
108
|
|
|
103
109
|
### 멀티 에이전트 (1.9.22, opt-in)
|
|
@@ -124,30 +130,19 @@ leerness update --from <tgz> # 오프라인/사내 미러
|
|
|
124
130
|
|
|
125
131
|
## 🤖 멀티 에이전트 오케스트레이션 (1.9.22)
|
|
126
132
|
|
|
127
|
-
|
|
128
|
-
**LLM 호출은 사용자 명시적 동의 후에만 활성화**. 환경변수 미설정 시 명령 거부:
|
|
133
|
+
**Opt-in 정책 ⚠** — LLM 호출은 사용자 명시적 동의 후에만 활성화. 환경변수 미설정 시 명령 거부 (`LEERNESS_OLLAMA_BASE_URL` 필수).
|
|
129
134
|
|
|
130
135
|
```bash
|
|
131
|
-
|
|
132
|
-
✗ LEERNESS_OLLAMA_BASE_URL 미설정 — orchestrate는 opt-in입니다.
|
|
133
|
-
정책 (1.9.22): 환경변수 없으면 LLM 호출 자동 시작 금지.
|
|
134
|
-
```
|
|
135
|
-
|
|
136
|
-
### 활성화
|
|
137
|
-
`.env` 파일에:
|
|
138
|
-
```bash
|
|
136
|
+
# 활성화 (.env)
|
|
139
137
|
LEERNESS_OLLAMA_BASE_URL=http://localhost:11434
|
|
140
138
|
LEERNESS_OLLAMA_MODEL=qwen2.5:7b-instruct # 선택
|
|
141
|
-
```
|
|
142
139
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
leerness orchestrate "
|
|
146
|
-
leerness orchestrate "복잡한 기능" --agents 20 # 큰 작업
|
|
140
|
+
# 가변 sub-agent
|
|
141
|
+
leerness orchestrate "함수 작성" --agents 3
|
|
142
|
+
leerness orchestrate "복잡한 기능" --agents 20
|
|
147
143
|
```
|
|
148
144
|
|
|
149
|
-
실측 병렬 효과:
|
|
150
|
-
- 3 agent: 1.9× / 5 agent: 3.2× / 10 agent: 5.5×
|
|
145
|
+
실측 병렬 효과: 3 agent 1.9× / 5 agent 3.2× / 10 agent 5.5×.
|
|
151
146
|
|
|
152
147
|
---
|
|
153
148
|
|
|
@@ -157,10 +152,9 @@ leerness orchestrate "복잡한 기능" --agents 20 # 큰 작업
|
|
|
157
152
|
|
|
158
153
|
| 명령 | 동작 |
|
|
159
154
|
|---|---|
|
|
160
|
-
| `
|
|
161
|
-
| `
|
|
162
|
-
| `
|
|
163
|
-
| `LEERNESS_OFFLINE=1` | npm 호출 건너뜀 |
|
|
155
|
+
| `update --check` | `HARNESS_VERSION` ↔ `npm view leerness version` 비교 |
|
|
156
|
+
| `update --yes` | 백업 → 마이그레이션 → verify/audit → 로그 누적 |
|
|
157
|
+
| `update --from <tarball>` | 로컬/오프라인/사내 미러 · `LEERNESS_OFFLINE=1` npm 스킵 |
|
|
164
158
|
|
|
165
159
|
---
|
|
166
160
|
|
|
@@ -169,8 +163,7 @@ leerness orchestrate "복잡한 기능" --agents 20 # 큰 작업
|
|
|
169
163
|
- 모든 변경 전 `.harness/archive/leerness-<version>-<timestamp>/` 자동 백업
|
|
170
164
|
- 사용자 메모리 (`plan`, `progress`, `decisions`, `task-log`, `architecture`, `reuse-map` 등) **항상 보존**
|
|
171
165
|
- 관리 인스트럭션 (`AGENTS.md`, `CLAUDE.md`, `.cursor/rules/leerness.mdc`, `.github/copilot-instructions.md`)은 새 템플릿으로 머지하되 이전 내용을 `<!-- leerness:migration-preserved -->` 블록 안에 보존
|
|
172
|
-
- `.env.example` / `.gitignore` / `.gitattributes`는 라인 단위 머지
|
|
173
|
-
- 결과 보고: `.harness/migration-report.md`
|
|
166
|
+
- `.env.example` / `.gitignore` / `.gitattributes`는 라인 단위 머지 · 결과 보고: `.harness/migration-report.md`
|
|
174
167
|
|
|
175
168
|
---
|
|
176
169
|
|
|
@@ -179,35 +172,35 @@ leerness orchestrate "복잡한 기능" --agents 20 # 큰 작업
|
|
|
179
172
|
```
|
|
180
173
|
.harness/
|
|
181
174
|
├── plan.md · progress-tracker.md · current-state.md · session-handoff.md
|
|
182
|
-
├── decisions.md · task-log.md · review-evidence.md
|
|
183
|
-
├──
|
|
184
|
-
├──
|
|
185
|
-
├── design-system.md · consistency-policy.md · reuse-map.md
|
|
175
|
+
├── decisions.md · task-log.md · review-evidence.md · guideline.md
|
|
176
|
+
├── architecture.md · context-map.md · feature-contracts.md · reuse-map.md
|
|
177
|
+
├── design-system.md · consistency-policy.md · writeback-policy.md
|
|
186
178
|
├── anti-lazy-work-policy.md · secret-policy.md · encoding-policy.md
|
|
187
179
|
├── protected-files.md · guardrails.md · language-policy.md
|
|
188
|
-
├── orchestrate-log.md
|
|
189
|
-
├── skill-index.md · skills/<id>/
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
.
|
|
193
|
-
├── commands/ · skills/leerness.md · settings.local.json
|
|
194
|
-
.cursor/rules/leerness.mdc
|
|
195
|
-
.github/copilot-instructions.md
|
|
196
|
-
AGENTS.md · CLAUDE.md
|
|
180
|
+
├── orchestrate-log.md · llm-bench-history.md (1.9.22+)
|
|
181
|
+
├── skill-index.md · skills/<id>/ · templates/
|
|
182
|
+
|
|
183
|
+
.claude/ (commands · skills · settings.local.json) · .cursor/rules/leerness.mdc
|
|
184
|
+
.github/copilot-instructions.md · AGENTS.md · CLAUDE.md
|
|
197
185
|
```
|
|
198
186
|
|
|
199
187
|
---
|
|
200
188
|
|
|
201
189
|
## 🧪 자동 검수 도구 매트릭스
|
|
202
190
|
|
|
203
|
-
| 도구 | 검출 |
|
|
191
|
+
| 도구 | 검출 | 추가 |
|
|
204
192
|
|---|---|---|
|
|
205
|
-
| `verify-claim T-XXX` | evidence
|
|
206
|
-
| `verify-claim --run-tests` | + 실제 `npm test` 실행 + pass 파싱
|
|
207
|
-
| `
|
|
208
|
-
| `
|
|
209
|
-
| `
|
|
210
|
-
| `
|
|
193
|
+
| `verify-claim T-XXX` | evidence 파일 존재 + 테스트 카운트 ≥ 주장 | 1.9.18 |
|
|
194
|
+
| `verify-claim --run-tests` | + 실제 `npm test` 실행 + pass 파싱 | 1.9.19/20 |
|
|
195
|
+
| `verify-claim --strict-claims` | + 낙관적 표시 검사 통합 | 1.9.26 |
|
|
196
|
+
| `optimism-check T-XXX` | 10 카테고리 + URL 매핑 + 신뢰도 점수 | 1.9.26/27 |
|
|
197
|
+
| `deps <capability>` | depends-on 역추적 + 자동 회귀 sweep | 1.9.24 |
|
|
198
|
+
| `memory search --include-code` | 소스 코드 본문 인덱싱/검색 | 1.9.25 |
|
|
199
|
+
| `register-pending` | 다중 세션 즉시 신호 | 1.9.25 |
|
|
200
|
+
| `reuse-map --strict-elements` | 함수명 동일 / capability 다른 잠재 중복 | 1.9.18 |
|
|
201
|
+
| `handoff --since 24h` | 최근 변경 T-row 자동 강조 | 1.9.18 |
|
|
202
|
+
| `verify-code --bench` | `scripts.bench` 자동 실행 + 누적 | 1.9.20 |
|
|
203
|
+
| `lazy detect` | 증거 없는 done · 빈 handoff · 추적 없는 TODO | 1.9.7 |
|
|
211
204
|
| `orchestrate --agents N` | 다중 LLM 동시 호출 (opt-in) | 1.9.22 |
|
|
212
205
|
| `handoff --compact` | LLM 시스템 프롬프트용 압축 출력 | 1.9.22 |
|
|
213
206
|
|
|
@@ -226,14 +219,36 @@ AGENTS.md · CLAUDE.md
|
|
|
226
219
|
|
|
227
220
|
---
|
|
228
221
|
|
|
222
|
+
## 🔬 낙관적 표시 방지 (1.9.26/27)
|
|
223
|
+
|
|
224
|
+
evidence에 "API 호출 완료" / "DB 저장 1000건" 같이 외부 작용을 적었지만 실제 코드에 호출 흔적이 없는 경우를 정적 분석으로 자동 감지.
|
|
225
|
+
|
|
226
|
+
### 10 카테고리 (1.9.27)
|
|
227
|
+
| 영역 | evidence 패턴 | 코드 흔적 |
|
|
228
|
+
|---|---|---|
|
|
229
|
+
| API | `API 호출 / POST /` | `fetch( / axios / http.request` |
|
|
230
|
+
| DB | `DB 저장 / insert N건` | `db. / pg. / mongoose. / prisma.` |
|
|
231
|
+
| Email | `이메일 발송 / sendMail` | `nodemailer / smtp / sendgrid` |
|
|
232
|
+
| Webhook | `웹훅 호출` | `fetch / axios.` |
|
|
233
|
+
| Payment | `결제 완료 / stripe` | `stripe / toss / iamport` |
|
|
234
|
+
| FileIO | `파일 N개 생성` | `fs.write / appendFile` |
|
|
235
|
+
| Queue | `메시지 큐 발행` | `amqp / kafkajs / bull` |
|
|
236
|
+
| Cache | `Redis 저장` | `redis. / ioredis` |
|
|
237
|
+
| Notify | `슬랙 알림` | `slack / discord.js` |
|
|
238
|
+
| Storage | `S3 업로드` | `aws-sdk/client-s3` |
|
|
239
|
+
|
|
240
|
+
**URL/메서드 단위 매핑 (1.9.27 핵심)** — evidence에 `POST /users`가 있으면 코드에서 실제 `/users` 경로 호출 검사. 못 찾으면 의심 발견. **신뢰도 점수** 0~1 출력 (< 0.5 ⚠ 낮음 / < 0.9 ⓘ 보통 / ≥ 0.9 ✓ 높음).
|
|
241
|
+
|
|
242
|
+
```bash
|
|
243
|
+
leerness optimism-check T-0001 --path .
|
|
244
|
+
leerness verify-claim T-0001 --run-tests --strict-claims
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
---
|
|
248
|
+
|
|
229
249
|
## 🤝 Claude Code 통합
|
|
230
250
|
|
|
231
|
-
설치 시 자동 등록:
|
|
232
|
-
- `.claude/commands/{handoff, session-close, audit, lazy-detect, update}.md`
|
|
233
|
-
- `.claude/skills/leerness.md` — Claude Code 스킬 정의
|
|
234
|
-
- `.claude/settings.local.json` — SessionStart hook (`update --check`)
|
|
235
|
-
- `.cursor/rules/leerness.mdc` — Cursor
|
|
236
|
-
- `.github/copilot-instructions.md` — Copilot
|
|
251
|
+
설치 시 자동 등록: `.claude/commands/{handoff, session-close, audit, lazy-detect, update}.md` · `.claude/skills/leerness.md` (스킬 정의) · `.claude/settings.local.json` (SessionStart hook `update --check`) · `.cursor/rules/leerness.mdc` (Cursor) · `.github/copilot-instructions.md` (Copilot)
|
|
237
252
|
|
|
238
253
|
---
|
|
239
254
|
|
|
@@ -281,16 +296,16 @@ leerness skill consolidate
|
|
|
281
296
|
## ❓ FAQ
|
|
282
297
|
|
|
283
298
|
**Q. leerness가 내 코드를 변경하나요?**
|
|
284
|
-
A. 사용자 메모리(plan/progress/decisions/architecture/reuse-map 등)는 **항상 보존**. 관리
|
|
299
|
+
A. 사용자 메모리(plan/progress/decisions/architecture/reuse-map 등)는 **항상 보존**. 관리 인스트럭션은 머지 + preserved 블록 보존. 모든 변경 전 `.harness/archive/`에 자동 백업.
|
|
285
300
|
|
|
286
301
|
**Q. 로컬 LLM을 사용하지 않고 싶어요.**
|
|
287
|
-
A. 기본 동작입니다. `LEERNESS_OLLAMA_BASE_URL`
|
|
302
|
+
A. 기본 동작입니다. `LEERNESS_OLLAMA_BASE_URL` 미설정 시 LLM 호출 절대 발생 안 함. `orchestrate` 명령만 거부 (다른 명령은 LLM 없이 동작).
|
|
288
303
|
|
|
289
304
|
**Q. CI에서 사용 가능?**
|
|
290
|
-
A. 네. `--json`
|
|
305
|
+
A. 네. `--json` (retro/insights/brainstorm/handoff/reuse-map/verify-claim) + exit code 통합. `verify-claim T-XXX --run-tests --json | jq '.verdict.runTests'`.
|
|
291
306
|
|
|
292
307
|
**Q. 다른 워크스페이스 모드 명령은?**
|
|
293
|
-
A. `--all-apps`는 현재 디렉토리 + `_apps/*` (또는 부모의 `_apps/*`)의 모든 leerness
|
|
308
|
+
A. `--all-apps`는 현재 디렉토리 + `_apps/*` (또는 부모의 `_apps/*`)의 모든 leerness 프로젝트 발견. `--include p1,p2`로 명시도 가능.
|
|
294
309
|
|
|
295
310
|
---
|
|
296
311
|
|
|
@@ -300,12 +315,17 @@ A. `--all-apps`는 현재 디렉토리 + `_apps/*` (또는 부모의 `_apps/*`)
|
|
|
300
315
|
npm test # = node ./scripts/e2e.js
|
|
301
316
|
```
|
|
302
317
|
|
|
303
|
-
**
|
|
318
|
+
**135/135 시나리오** 통과 (1.9.7~1.9.27 회귀 + 신규 검증).
|
|
304
319
|
|
|
305
320
|
---
|
|
306
321
|
|
|
307
322
|
## 📜 변경 이력 (최근)
|
|
308
323
|
|
|
324
|
+
- **1.9.27** — `optimism-check` 강화: 10 카테고리 + URL/메서드 매핑 + 신뢰도 점수
|
|
325
|
+
- **1.9.26** — `optimism-check <T-ID>`, `verify-claim --strict-claims` (낙관적 표시 방지)
|
|
326
|
+
- **1.9.25** — `--include-code` (소스 코드 인덱싱), `register-pending` (다중 세션)
|
|
327
|
+
- **1.9.24** — `deps <capability>` (depends-on 역추적 + 자동 회귀)
|
|
328
|
+
- **1.9.23** — `preferGlobal`, README Install 가이드
|
|
309
329
|
- **1.9.22** — Ollama opt-in 통합 (`orchestrate --agents N`), `handoff --compact`, `llm-bench record`
|
|
310
330
|
- **1.9.21** — `.cfg`/`.ini`/`.env`/`.toml`/`.lock` 메타 파일 verify-claim regex 확장
|
|
311
331
|
- **1.9.20** — Godot/jest/mocha 지원, `verify-code --bench`, file regex 도메인 폴더 자동 인식
|
package/bin/harness.js
CHANGED
|
@@ -6,7 +6,7 @@ const path = require('path');
|
|
|
6
6
|
const cp = require('child_process');
|
|
7
7
|
const readline = require('readline');
|
|
8
8
|
|
|
9
|
-
const VERSION = '1.9.
|
|
9
|
+
const VERSION = '1.9.27';
|
|
10
10
|
const MARK = '<!-- leerness:managed -->';
|
|
11
11
|
const README_START = '<!-- leerness:project-readme:start -->';
|
|
12
12
|
const README_END = '<!-- leerness:project-readme:end -->';
|
|
@@ -2035,8 +2035,9 @@ function depsImpactCmd(root, targetCapability) {
|
|
|
2035
2035
|
// evidence에 "API 호출" / "HTTP 200|201" / "POST /" / "응답 확인" → 코드에 fetch/http.request/axios 흔적 없으면 의심
|
|
2036
2036
|
// evidence에 "DB 저장" / "insert N건" / "DB에" → db.*/pg.*/mysql.*/mongoose.*/prisma.* 없으면 의심
|
|
2037
2037
|
// evidence에 "이메일 발송" / "메일 전송" → sendMail/nodemailer/smtp 없으면 의심
|
|
2038
|
+
// 1.9.27: 패턴 카탈로그 확장 (5 → 10) + URL/메서드 단위 매핑 추가
|
|
2038
2039
|
const OPTIMISM_PATTERNS = [
|
|
2039
|
-
{ kind: 'API', evidenceRe: /(API\s*호출|HTTP\s*\d{3}|POST\s*\/|GET\s*\/|PUT\s*\/|DELETE\s*\/|fetch|REST 응답|응답 확인|endpoint)/i,
|
|
2040
|
+
{ kind: 'API', evidenceRe: /(API\s*호출|HTTP\s*\d{3}|POST\s*\/|GET\s*\/|PUT\s*\/|DELETE\s*\/|fetch|REST 응답|응답 확인|endpoint|엔드포인트)/i,
|
|
2040
2041
|
codeRe: /\b(fetch\s*\(|http\.request|https\.request|axios\.|got\.|undici|node-fetch)/i,
|
|
2041
2042
|
label: 'API/HTTP 호출' },
|
|
2042
2043
|
{ kind: 'DB', evidenceRe: /(DB에?\s*저장|insert\s+\d+|데이터베이스|SQL\s*(INSERT|UPDATE|DELETE)|migration|마이그레이션 적용)/i,
|
|
@@ -2045,14 +2046,50 @@ const OPTIMISM_PATTERNS = [
|
|
|
2045
2046
|
{ kind: 'Email', evidenceRe: /(이메일[^.\n]{0,30}(발송|전송|보냈|보냄|완료)|메일[^.\n]{0,30}(발송|전송|보냈|보냄)|sendMail|smtp\s*(전송|발송))/i,
|
|
2046
2047
|
codeRe: /\b(sendMail|nodemailer|smtp|@sendgrid|mailgun|aws-sdk\/ses|resend\.)/i,
|
|
2047
2048
|
label: '이메일 전송' },
|
|
2048
|
-
{ kind: 'Webhook', evidenceRe: /(웹훅\s*(
|
|
2049
|
+
{ kind: 'Webhook', evidenceRe: /(웹훅\s*(호출|전송|발송)|webhook\s+(sent|posted|triggered))/i,
|
|
2049
2050
|
codeRe: /\b(fetch\s*\(|http\.request|axios\.)/i,
|
|
2050
2051
|
label: '웹훅' },
|
|
2051
|
-
{ kind: 'Payment', evidenceRe: /(결제\s*(완료|성공)|payment\s+(processed|charged)|stripe|
|
|
2052
|
-
codeRe: /\b(stripe|toss|@stripe|tosspayments|iamport)/i,
|
|
2053
|
-
label: '결제' }
|
|
2052
|
+
{ kind: 'Payment', evidenceRe: /(결제\s*(완료|성공)|payment\s+(processed|charged)|stripe 결제|toss\s*결제|카카오페이|kakaopay|nicepay|iamport 결제)/i,
|
|
2053
|
+
codeRe: /\b(stripe|toss|@stripe|tosspayments|iamport|kakao|nicepay)/i,
|
|
2054
|
+
label: '결제' },
|
|
2055
|
+
// 1.9.27 신규 카테고리
|
|
2056
|
+
{ kind: 'FileIO', evidenceRe: /(파일[^.\n]{0,20}(생성|저장|작성|기록)|\d+개[^.\n]{0,20}파일|디스크[^.\n]{0,20}저장|로그 파일 작성)/i,
|
|
2057
|
+
codeRe: /\b(fs\.write|fs\.appendFile|writeFileSync|appendFileSync|fs\/promises|fs\.createWriteStream)/i,
|
|
2058
|
+
label: '파일 I/O 쓰기' },
|
|
2059
|
+
{ kind: 'Queue', evidenceRe: /(메시지\s*큐|발행\s*완료|publish\s*(완료|성공)|RabbitMQ|Kafka|SQS|Redis Pub|이벤트 발행)/i,
|
|
2060
|
+
codeRe: /\b(amqp|kafkajs|rabbit|redis\.(publish|xadd)|@aws-sdk\/client-sqs|bull|bullmq)/i,
|
|
2061
|
+
label: '메시지 큐 발행' },
|
|
2062
|
+
{ kind: 'Cache', evidenceRe: /(Redis[^.\n]{0,20}(저장|set|get)|캐시[^.\n]{0,20}(저장|기록|적중)|memcache)/i,
|
|
2063
|
+
codeRe: /\b(redis\.|ioredis|memcached|node-cache|@upstash\/redis|connect-redis)/i,
|
|
2064
|
+
label: '캐시 저장' },
|
|
2065
|
+
{ kind: 'Notify', evidenceRe: /(슬랙\s*(알림|발송|전송)|Slack\s+(notification|sent|posted)|Discord\s+(알림|발송|webhook)|푸시 알림 전송)/i,
|
|
2066
|
+
codeRe: /\b(@slack\/web-api|slack-webhook|discord\.js|discord-webhook|@discordjs|firebase\/messaging|expo-notifications)/i,
|
|
2067
|
+
label: '슬랙/Discord 알림' },
|
|
2068
|
+
{ kind: 'Storage', evidenceRe: /(S3\s*(업로드|저장)|GCS\s*업로드|Azure Blob|클라우드 스토리지 업로드|object storage 저장)/i,
|
|
2069
|
+
codeRe: /\b(@aws-sdk\/client-s3|aws-sdk[^a-z]|@google-cloud\/storage|@azure\/storage-blob|aws-s3)/i,
|
|
2070
|
+
label: '클라우드 스토리지' }
|
|
2054
2071
|
];
|
|
2055
2072
|
|
|
2073
|
+
// 1.9.27: URL/메서드 단위 매핑 — evidence에서 "POST /users" 같은 구체 경로를 추출하고 코드에 같은 경로 존재 확인
|
|
2074
|
+
function _extractUrlClaims(evidence) {
|
|
2075
|
+
const claims = [];
|
|
2076
|
+
// "POST /users" / "GET /api/v1/items" 등
|
|
2077
|
+
const re = /\b(GET|POST|PUT|DELETE|PATCH)\s+(\/[\w\-\/]*)/gi;
|
|
2078
|
+
let m;
|
|
2079
|
+
while ((m = re.exec(evidence)) !== null) {
|
|
2080
|
+
claims.push({ method: m[1].toUpperCase(), path: m[2] });
|
|
2081
|
+
}
|
|
2082
|
+
return claims;
|
|
2083
|
+
}
|
|
2084
|
+
function _verifyUrlClaim(claim, codeText) {
|
|
2085
|
+
// claim.path 가 코드에 등장해야 함 (fetch('https://.../users') 또는 라우트 정의 'POST /users')
|
|
2086
|
+
if (!claim.path || claim.path.length < 2) return true;
|
|
2087
|
+
// path를 그대로 검색 (URL 또는 라우트 정의)
|
|
2088
|
+
const escaped = claim.path.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
2089
|
+
const re = new RegExp(escaped, 'i');
|
|
2090
|
+
return re.test(codeText);
|
|
2091
|
+
}
|
|
2092
|
+
|
|
2056
2093
|
function _scanCodeForPatterns(root) {
|
|
2057
2094
|
// src/, bin/, lib/, scripts/ 의 .js/.ts/.gd/.py 파일 본문 통합
|
|
2058
2095
|
let combined = '';
|
|
@@ -2079,12 +2116,38 @@ function _detectOptimism(evidence, codeText) {
|
|
|
2079
2116
|
const suspects = [];
|
|
2080
2117
|
for (const p of OPTIMISM_PATTERNS) {
|
|
2081
2118
|
if (p.evidenceRe.test(evidence) && !p.codeRe.test(codeText)) {
|
|
2082
|
-
suspects.push({ kind: p.kind, label: p.label });
|
|
2119
|
+
suspects.push({ kind: p.kind, label: p.label, severity: 'high' });
|
|
2120
|
+
}
|
|
2121
|
+
}
|
|
2122
|
+
// 1.9.27: URL/메서드 단위 매핑 — API 패턴에선 통과해도 구체 경로가 코드에 없으면 추가 의심
|
|
2123
|
+
const urlClaims = _extractUrlClaims(evidence);
|
|
2124
|
+
for (const claim of urlClaims) {
|
|
2125
|
+
if (!_verifyUrlClaim(claim, codeText)) {
|
|
2126
|
+
suspects.push({
|
|
2127
|
+
kind: 'URL',
|
|
2128
|
+
label: `구체 경로 "${claim.method} ${claim.path}" 코드에 미발견`,
|
|
2129
|
+
severity: 'medium',
|
|
2130
|
+
claim
|
|
2131
|
+
});
|
|
2083
2132
|
}
|
|
2084
2133
|
}
|
|
2085
2134
|
return suspects;
|
|
2086
2135
|
}
|
|
2087
2136
|
|
|
2137
|
+
// 1.9.27: 신뢰도 점수 (0=완전 의심, 1=신뢰)
|
|
2138
|
+
function _computeConfidence(evidence, codeText) {
|
|
2139
|
+
const suspects = _detectOptimism(evidence, codeText);
|
|
2140
|
+
const high = suspects.filter(s => s.severity === 'high').length;
|
|
2141
|
+
const medium = suspects.filter(s => s.severity === 'medium').length;
|
|
2142
|
+
// 가중치: high 1.0 / medium 0.5
|
|
2143
|
+
const totalPenalty = high * 1.0 + medium * 0.5;
|
|
2144
|
+
// 패턴 검사로 발견된 evidence 주장이 많을수록 신뢰도 산정 base 변경
|
|
2145
|
+
const evidenceClaims = OPTIMISM_PATTERNS.filter(p => p.evidenceRe.test(evidence)).length + _extractUrlClaims(evidence).length;
|
|
2146
|
+
if (evidenceClaims === 0) return 1.0; // 외부 작용 주장 자체가 없으면 신뢰 1.0
|
|
2147
|
+
const confidence = Math.max(0, 1 - totalPenalty / evidenceClaims);
|
|
2148
|
+
return Math.round(confidence * 100) / 100;
|
|
2149
|
+
}
|
|
2150
|
+
|
|
2088
2151
|
function optimismCheckCmd(root, taskId) {
|
|
2089
2152
|
root = absRoot(root || process.cwd());
|
|
2090
2153
|
if (!taskId) return fail('optimism-check <T-ID> 필요. 예: leerness optimism-check T-0001');
|
|
@@ -2094,11 +2157,13 @@ function optimismCheckCmd(root, taskId) {
|
|
|
2094
2157
|
|
|
2095
2158
|
const codeText = _scanCodeForPatterns(root);
|
|
2096
2159
|
const suspects = _detectOptimism(row.evidence || '', codeText);
|
|
2160
|
+
const confidence = _computeConfidence(row.evidence || '', codeText);
|
|
2097
2161
|
|
|
2098
2162
|
if (has('--json')) {
|
|
2099
2163
|
log(JSON.stringify({
|
|
2100
2164
|
project: path.basename(root), taskId, row,
|
|
2101
|
-
suspects,
|
|
2165
|
+
suspects, confidence,
|
|
2166
|
+
ok: suspects.length === 0,
|
|
2102
2167
|
codeFilesScanned: codeText.length > 0
|
|
2103
2168
|
}, null, 2));
|
|
2104
2169
|
if (suspects.length > 0) return process.exit(1);
|
|
@@ -2107,13 +2172,17 @@ function optimismCheckCmd(root, taskId) {
|
|
|
2107
2172
|
|
|
2108
2173
|
log(`# leerness optimism-check ${taskId} (${path.basename(root)})`);
|
|
2109
2174
|
log(`Evidence: ${(row.evidence || '').slice(0, 200)}${(row.evidence || '').length > 200 ? '…' : ''}`);
|
|
2175
|
+
log(`신뢰도 (1.9.27): ${confidence.toFixed(2)} / 1.00${confidence < 0.5 ? ' ⚠ 낮음' : confidence < 0.9 ? ' ⓘ 보통' : ' ✓ 높음'}`);
|
|
2110
2176
|
log('');
|
|
2111
2177
|
if (!suspects.length) {
|
|
2112
2178
|
log(` ✓ 낙관적 표시 의심 없음 — evidence의 주장이 실제 코드 호출 흔적과 일관`);
|
|
2113
2179
|
return;
|
|
2114
2180
|
}
|
|
2115
2181
|
log(` ⚠ 낙관적 표시 의심 ${suspects.length}건 — evidence에 주장 있는데 코드에 호출 흔적 없음`);
|
|
2116
|
-
for (const s of suspects)
|
|
2182
|
+
for (const s of suspects) {
|
|
2183
|
+
const sev = s.severity === 'high' ? '⚠ HIGH' : 'ⓘ MED';
|
|
2184
|
+
log(` · [${s.kind}] ${sev} ${s.label}`);
|
|
2185
|
+
}
|
|
2117
2186
|
log('');
|
|
2118
2187
|
log(`💡 가능한 해석:`);
|
|
2119
2188
|
log(` 1) evidence 작성자가 실제 동작 없이 낙관적으로 표시 (검증 필요)`);
|
|
@@ -4208,7 +4277,7 @@ function viewworkInstall(root) {
|
|
|
4208
4277
|
}
|
|
4209
4278
|
|
|
4210
4279
|
function help() {
|
|
4211
|
-
log(`Leerness v${VERSION}\n\nUsage:\n leerness init [path] [--language auto|ko|en] [--skills recommended|all|a,b]\n leerness migrate [path] [--dry-run] [--force]\n leerness update [path] [--check|--yes|--force|--from <tarball>]\n leerness auto-update install [path]\n leerness status [path]\n leerness verify [path]\n leerness debug [path]\n leerness audit [path]\n leerness check [path]\n leerness scan secrets [path]\n leerness encoding check [path]\n leerness lazy detect [path]\n leerness memory search "query" [--limit 5]\n leerness handoff [path] [--all-apps] [--include p1,p2] [--since 24h|3d] [--compact] [--json] # 1.9.17-22 워크스페이스 (--compact: LLM 시스템 프롬프트용 1줄 요약)\n leerness orchestrate "<목표>" [--agents N] [--model qwen2.5:7b-instruct] [--retry-on-fail K] # 1.9.22 Ollama opt-in (LEERNESS_OLLAMA_BASE_URL 필요)\n leerness llm-bench record --score N --model X [--label L] [--tokens T] # 1.9.22 LLM 벤치 히스토리 누적\n leerness deps <capability> [--run-tests] [--json] # 1.9.24 depends-on 역방향 추적 + 자동 회귀 sweep\n leerness memory search "키" [--include-code] # 1.9.25 소스 코드 본문도 검색 (모순 감지 핵심)\n leerness brainstorm "주제" [--include-code] # 1.9.25 코드 본문 hits 포함\n leerness register-pending "<요청>" [--agent X] [--note Y] # 1.9.25 다중 세션 in-progress 즉시 등록\n leerness optimism-check <T-ID> [--json] # 1.9.26 낙관적 표시 감지 (
|
|
4280
|
+
log(`Leerness v${VERSION}\n\nUsage:\n leerness init [path] [--language auto|ko|en] [--skills recommended|all|a,b]\n leerness migrate [path] [--dry-run] [--force]\n leerness update [path] [--check|--yes|--force|--from <tarball>]\n leerness auto-update install [path]\n leerness status [path]\n leerness verify [path]\n leerness debug [path]\n leerness audit [path]\n leerness check [path]\n leerness scan secrets [path]\n leerness encoding check [path]\n leerness lazy detect [path]\n leerness memory search "query" [--limit 5]\n leerness handoff [path] [--all-apps] [--include p1,p2] [--since 24h|3d] [--compact] [--json] # 1.9.17-22 워크스페이스 (--compact: LLM 시스템 프롬프트용 1줄 요약)\n leerness orchestrate "<목표>" [--agents N] [--model qwen2.5:7b-instruct] [--retry-on-fail K] # 1.9.22 Ollama opt-in (LEERNESS_OLLAMA_BASE_URL 필요)\n leerness llm-bench record --score N --model X [--label L] [--tokens T] # 1.9.22 LLM 벤치 히스토리 누적\n leerness deps <capability> [--run-tests] [--json] # 1.9.24 depends-on 역방향 추적 + 자동 회귀 sweep\n leerness memory search "키" [--include-code] # 1.9.25 소스 코드 본문도 검색 (모순 감지 핵심)\n leerness brainstorm "주제" [--include-code] # 1.9.25 코드 본문 hits 포함\n leerness register-pending "<요청>" [--agent X] [--note Y] # 1.9.25 다중 세션 in-progress 즉시 등록\n leerness optimism-check <T-ID> [--json] # 1.9.26/27 낙관적 표시 감지 (1.9.27: 10 카테고리 + URL/메서드 매핑 + 신뢰도 점수)\n leerness verify-claim <T-ID> ... [--strict-claims] # 1.9.26 verify-claim에 낙관적 표시 자동 검사 통합\n leerness reuse-map [path] [--all-apps] [--include p1,p2] [--strict-elements] [--json] # 1.9.18 중복/잠재중복/depends-on\n leerness verify-claim <T-ID> [--path .] [--run-tests] [--json] # 1.9.18-20 evidence 자동 검증 (1.9.20: scenes/scripts 등 도메인 폴더 + jest/mocha 파싱)\n leerness verify-code [path] [--build] [--bench] # 1.9.20 --bench: scripts.bench 추가 실행 + evidence 누적\n leerness session close [path]\n leerness viewwork install [path]\n leerness viewwork emit [path] [--action a] [--note n] [--agent x] [--tool t]\n leerness route <task-type>\n leerness self check [path]\n leerness readme sync [path]\n leerness consistency check [path]\n leerness consistency merge-design-guide [path]\n leerness plan show|init|add|drop|progress|sync [args]\n leerness task list|add|update|drop|fix-evidence|relink [args]\n leerness skill list|info <name>\n leerness skill learn <id> --doc <url> --command "..." --capability "..." [--note ...]\n leerness skill use <id> [--note ...]\n leerness skill optimize <id> --before "..." --after "..." [--note ...]\n leerness skill remove <id>\n leerness skill consolidate [--threshold 0.3]\n leerness gate [path] # verify+audit+scan+encoding+lazy
|
|
4212
4281
|
leerness retro [path] [--days 7] [--all-apps] [--include p1,p2] [--json] # 회고 (1.9.13~1.9.16)
|
|
4213
4282
|
leerness insights [path] [--all-apps] [--include p1,p2] [--json] # 누적 통계 (1.9.13~1.9.16)
|
|
4214
4283
|
leerness brainstorm "<주제>" [--all-apps] [--include p1,p2] [--json] # 브레인스토밍 (1.9.13~1.9.16)
|
package/package.json
CHANGED
package/scripts/e2e.js
CHANGED
|
@@ -656,6 +656,59 @@ total++;
|
|
|
656
656
|
if (!ok) { failed++; console.log(r.stdout.slice(0, 400)); }
|
|
657
657
|
}
|
|
658
658
|
|
|
659
|
+
// 1.9.27 회귀: URL/메서드 매핑 + 신뢰도 점수 + 신규 카테고리 (FileIO/Queue/Cache/Notify/Storage)
|
|
660
|
+
total++;
|
|
661
|
+
{
|
|
662
|
+
// T-9001 false negative 해결 검증: 코드에 다른 목적의 http.request 있어도 URL 미매치로 잡아냄
|
|
663
|
+
const tmpU = fs.mkdtempSync(path.join(os.tmpdir(), 'leerness-url-'));
|
|
664
|
+
cp.spawnSync(process.execPath, [CLI, 'init', tmpU, '--yes', '--language', 'ko', '--skills', 'recommended'], { stdio: 'ignore', timeout: 30000 });
|
|
665
|
+
fs.mkdirSync(path.join(tmpU, 'src'), { recursive: true });
|
|
666
|
+
// 다른 목적의 http.request (Ollama 호출 패턴)
|
|
667
|
+
fs.writeFileSync(path.join(tmpU, 'src/ollama.js'), "http.request({host:'localhost',path:'/api/tags',method:'GET'})");
|
|
668
|
+
// evidence: 전혀 다른 경로 주장
|
|
669
|
+
fs.appendFileSync(path.join(tmpU, '.harness/progress-tracker.md'),
|
|
670
|
+
'| T-9001 | done | API 사용자 등록 | POST /users API 호출 완료, HTTP 201 응답 확인 | next | 2026-05-15 |\n');
|
|
671
|
+
const r = cp.spawnSync(process.execPath, [CLI, 'optimism-check', 'T-9001', '--path', tmpU], { encoding: 'utf8', timeout: 10000 });
|
|
672
|
+
const ok = r.status !== 0
|
|
673
|
+
&& /\[URL\]/.test(r.stdout)
|
|
674
|
+
&& /POST \/users/.test(r.stdout)
|
|
675
|
+
&& /신뢰도 \(1\.9\.27\):/.test(r.stdout);
|
|
676
|
+
console.log(ok ? '✓ B(1.9.27) URL 매핑: 1.9.26 false negative 해결 (POST /users 미발견)' : '✗ URL 매핑 실패');
|
|
677
|
+
if (!ok) { failed++; console.log(r.stdout.slice(0, 500)); }
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
total++;
|
|
681
|
+
{
|
|
682
|
+
// 신규 카테고리 (Slack/Notify)
|
|
683
|
+
const tmpN = fs.mkdtempSync(path.join(os.tmpdir(), 'leerness-notify-'));
|
|
684
|
+
cp.spawnSync(process.execPath, [CLI, 'init', tmpN, '--yes', '--language', 'ko', '--skills', 'recommended'], { stdio: 'ignore', timeout: 30000 });
|
|
685
|
+
fs.mkdirSync(path.join(tmpN, 'src'), { recursive: true });
|
|
686
|
+
fs.writeFileSync(path.join(tmpN, 'src/x.js'), 'module.exports={};\n');
|
|
687
|
+
fs.appendFileSync(path.join(tmpN, '.harness/progress-tracker.md'),
|
|
688
|
+
'| T-9100 | done | Slack 알림 | 슬랙 알림 발송 완료, #general 채널에 통보 | next | 2026-05-15 |\n');
|
|
689
|
+
const r = cp.spawnSync(process.execPath, [CLI, 'optimism-check', 'T-9100', '--path', tmpN], { encoding: 'utf8', timeout: 10000 });
|
|
690
|
+
const ok = r.status !== 0 && /\[Notify\]/.test(r.stdout) && /슬랙\/Discord 알림/.test(r.stdout);
|
|
691
|
+
console.log(ok ? '✓ B(1.9.27) 신규 카테고리 Notify: 슬랙 알림 거짓 감지' : '✗ Notify 카테고리 실패');
|
|
692
|
+
if (!ok) { failed++; console.log(r.stdout.slice(0, 400)); }
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
total++;
|
|
696
|
+
{
|
|
697
|
+
// 신뢰도 점수 — 정상 케이스는 1.0
|
|
698
|
+
const tmpC = fs.mkdtempSync(path.join(os.tmpdir(), 'leerness-conf-'));
|
|
699
|
+
cp.spawnSync(process.execPath, [CLI, 'init', tmpC, '--yes', '--language', 'ko', '--skills', 'recommended'], { stdio: 'ignore', timeout: 30000 });
|
|
700
|
+
fs.mkdirSync(path.join(tmpC, 'src'), { recursive: true });
|
|
701
|
+
fs.writeFileSync(path.join(tmpC, 'src/x.js'), 'module.exports={};\n');
|
|
702
|
+
fs.appendFileSync(path.join(tmpC, '.harness/progress-tracker.md'),
|
|
703
|
+
'| T-9200 | done | pure compute | src/x.js 모듈 추가 | next | 2026-05-15 |\n');
|
|
704
|
+
const r = cp.spawnSync(process.execPath, [CLI, 'optimism-check', 'T-9200', '--path', tmpC, '--json'], { encoding: 'utf8', timeout: 10000 });
|
|
705
|
+
let parsed = null;
|
|
706
|
+
try { parsed = JSON.parse(r.stdout); } catch {}
|
|
707
|
+
const ok = r.status === 0 && parsed && parsed.confidence === 1.0 && parsed.suspects.length === 0;
|
|
708
|
+
console.log(ok ? '✓ B(1.9.27) 신뢰도 점수: 정상 evidence → 1.00' : '✗ 신뢰도 점수 실패');
|
|
709
|
+
if (!ok) { failed++; console.log(r.stdout.slice(0, 400)); }
|
|
710
|
+
}
|
|
711
|
+
|
|
659
712
|
// 1.9.22 회귀: handoff --compact + orchestrate opt-in 정책 + llm-bench record
|
|
660
713
|
total++;
|
|
661
714
|
{
|