leerness 1.35.9 → 1.35.10
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 +13 -0
- package/README.md +4 -4
- package/bin/leerness.js +11 -1
- package/package.json +1 -1
- package/scripts/e2e.js +25 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.35.10 — 2026-07-06 — 자체 gate 적대적 헌트: 가드레일 검증(제품 결함 0) + 보안 동작 회귀 가드
|
|
4
|
+
|
|
5
|
+
**verify-claim(1.35.9)에 이어 인접 가드레일 `gate` 를 적대적으로 검증** — README 가 "required CI check 로 만들라"고 권하는 표면이라 FN(거짓완료 PR 통과)/FP(정직한 PR 차단)가 최악. 게시본 1.35.9 에 8-프로브 매트릭스(FP 4: 클린 프로젝트·bare init·placeholder·done+evidence / FN 3: 커밋 시크릿·거짓완료 --claims·필수파일 삭제 / by-design 1) 실행.
|
|
6
|
+
|
|
7
|
+
### 검증 결과 — **제품 결함 0**
|
|
8
|
+
- FP 4/4 OK(클린 프로젝트/placeholder 모두 통과, 오탐 없음), FN 3/3 OK(시크릿·거짓완료·구조결함 차단). 프로브가 낸 "🚨 FN" 2건은 모두 **프로브 아티팩트**(1건은 문서상 by-design 기본 5체크, 1건은 내 프로브의 `--path` 누락으로 done task 미생성) — 맹신 X 로 3-경로 재현해 제품 정상(gate --claims 는 올바른 셋업에서 거짓완료 차단 확인) 판명. 지난 라운드에 이어 실패 신호를 제품 회귀로 오인하지 않음.
|
|
9
|
+
|
|
10
|
+
### 회귀 가드 (유일 커버리지 갭)
|
|
11
|
+
- 기존 e2e(B(1.33.3)/B(1.34.1))는 `--claims` 콘텐츠 차원 중심 → gate 를 **보안 가드레일**로 보는 관점(커밋된 실키 차단 / placeholder 오탐 없음)이 gate 레벨 전용 가드가 없었음. e2e B(1.35.10) 추가: 정상 `.env.example` placeholder → 오탐 없이 통과(exit 0), 커밋된 실 AWS 키 → 차단(exit 1, scan secrets step 실패). selftest 에 gate 5체크 조합 고정(verify/audit/scan secrets/encoding/lazy detect + --claims 6번째) — scan-step 리팩터가 가드레일 보안을 조용히 무너뜨리는 회귀 차단.
|
|
12
|
+
|
|
13
|
+
### 검증
|
|
14
|
+
- selftest **270** (신규: gate 조합 고정). full e2e **383** (신규: gate 보안 가드레일 행위). 8-프로브 매트릭스 게시본 재실증(FP 0/FN 0).
|
|
15
|
+
|
|
3
16
|
## 1.35.9 — 2026-07-03 — 자체 적대적 FP 헌트: declared-pass 게이트를 완전-통과(N/N) 주장으로 한정 (1.35.7 후속 하드닝)
|
|
4
17
|
|
|
5
18
|
**1.35.7 에서 declared-pass 부풀림 게이팅을 넣은 뒤, 그 신규 게이트에 전용 FP/FN 헌트를 직접 돌림**(메모리 교훈: 「휴리스틱 적대적 하드닝 — 배포 전 bypass+FP 헌터」·「게시본 재실증」). 12-프로브 매트릭스(단일/`--json`/`--all`/`gate --claims` × 비율/카운트/spec·tap·jest 리포터/growth/lenient)를 게시본 1.35.8 에 실행 → **bypass(FN) 0, 정상 FP 0**, 단 1건의 진짜 false-positive 발견.
|
package/README.md
CHANGED
|
@@ -125,7 +125,7 @@ MIT
|
|
|
125
125
|
<!-- leerness:project-readme:start -->
|
|
126
126
|
## Leerness Project Harness
|
|
127
127
|
|
|
128
|
-
이 프로젝트는 Leerness v1.35.
|
|
128
|
+
이 프로젝트는 Leerness v1.35.10 하네스를 사용합니다. AI 에이전트는 작업 전 `leerness handoff`로 컨텍스트를 적재하고, 작업 후 `leerness check`/`leerness audit`/`leerness session close`를 수행해야 합니다.
|
|
129
129
|
|
|
130
130
|
### 정체성 — AI 에이전트 운영 레이어 (UR-0030)
|
|
131
131
|
|
|
@@ -179,7 +179,7 @@ leerness memory restore decision <date|title>
|
|
|
179
179
|
|
|
180
180
|
### MCP server (외부 AI 통합)
|
|
181
181
|
|
|
182
|
-
Leerness v1.35.
|
|
182
|
+
Leerness v1.35.10는 stdio JSON-RPC MCP server를 내장합니다 — Claude Code · Cursor · Codex CLI 등 외부 AI에 **86개 도구**를 노출:
|
|
183
183
|
|
|
184
184
|
```jsonc
|
|
185
185
|
// 카테고리별
|
|
@@ -200,7 +200,7 @@ Leerness v1.35.9는 stdio JSON-RPC MCP server를 내장합니다 — Claude Code
|
|
|
200
200
|
`<<autonomous-loop-dynamic>>` 신호만 보내면 AI가:
|
|
201
201
|
1) 다음 라운드 후보 선정 → 2) 코드 변경 → 3) stress-v* 신규 작성 + 누적 회귀 → 4) e2e 219/219 → 5) npm pack + git tag + GitHub release → 6) main 자동 push (1.9.140+) → 7) session close → 8) 다음 라운드 예약.
|
|
202
202
|
|
|
203
|
-
현재 누적: **70 라운드 (1.9.40 → 1.35.
|
|
203
|
+
현재 누적: **70 라운드 (1.9.40 → 1.35.10)** · 매 라운드 GitHub release/태그 생성 · _reports/는 비공개 보존.
|
|
204
204
|
|
|
205
205
|
### 성능 가이드 (1.9.140 측정)
|
|
206
206
|
|
|
@@ -238,6 +238,6 @@ leerness release pack --close --auto-main-push
|
|
|
238
238
|
- `.harness/session-handoff.md`: 다음 세션 인수인계 (자동 작성)
|
|
239
239
|
- `.harness/lessons.md` / `decisions.md` / `rules.md`: 영구 메모리 (5 surface)
|
|
240
240
|
|
|
241
|
-
Last synced by Leerness v1.35.
|
|
241
|
+
Last synced by Leerness v1.35.10: 2026-07-06
|
|
242
242
|
<!-- leerness:project-readme:end -->
|
|
243
243
|
|
package/bin/leerness.js
CHANGED
|
@@ -32,7 +32,7 @@ const { _evidenceQuality, _parseEvidenceStats, _shellGuardAnalyze, _claimFileInG
|
|
|
32
32
|
// 1.9.295 (UR-0025 4단계): 정적 데이터 카탈로그 모듈 분리 (비파괴, require-based).
|
|
33
33
|
const { CAPABILITY_SURFACE, POWERFUL_COMMANDS, ADAPTERS, REUSE_CATEGORIES, REUSE_CHECKLIST, _DEFAULT_PLATFORM_CONSTRAINTS, _DEFAULT_DOMAIN_CATALOG, _TOOL_CATALOG, _LSP_LANG_PATTERNS, OPTIMISM_PATTERNS, BUILT_IN_PERSONAS, STRINGS, BUILTIN_CATALOG, ROADMAP_STATUS_LABEL, ROADMAP_STATUS_COLOR, SECRET_PATTERNS, MERGE_OVERWRITE_FILES, MINIMAL_SKIP_KEYS, REQUIRED_WORKSPACE_FILES, KEYWORD_STOPWORDS, SKILL_CATALOG_PRESETS } = require('../lib/catalogs'); // 1.9.344/368/369 (UR-0025): catalog 분리 · 1.11.4 (UR-0007): _TOOL_CATALOG
|
|
34
34
|
|
|
35
|
-
const VERSION = '1.35.
|
|
35
|
+
const VERSION = '1.35.10';
|
|
36
36
|
|
|
37
37
|
// 1.9.290 (UR-0037, Codex gpt-5.5 #4 수렴): CLI 전용 부작용은 require 시 실행하지 않는다.
|
|
38
38
|
// 이전: warning listener 제거 / NODE_OPTIONS 변경 / chcp IIFE 가 top-level 즉시 실행 → require('harness') 시 호스트 프로세스 오염.
|
|
@@ -2925,6 +2925,16 @@ function _selfTestCases() {
|
|
|
2925
2925
|
const honestLabel = src.includes('부분 비율 — advisory, 게이트 제외') && src.includes('partial ratio — advisory, not gated');
|
|
2926
2926
|
return fullPassGuard && honestLabel;
|
|
2927
2927
|
} },
|
|
2928
|
+
{ name: '자체 gate 적대적 헌트 (1.35.10): gate 5체크 조합 고정(verify/audit/scan secrets/encoding/lazy detect) + --claims 6번째 — 보안 step 누락 회귀 차단', run: () => {
|
|
2929
|
+
const src = read(__filename);
|
|
2930
|
+
const i = src.indexOf('function gate(root)');
|
|
2931
|
+
if (i < 0) return false;
|
|
2932
|
+
const body = src.slice(i, i + 2200);
|
|
2933
|
+
// gate 가 5개 코어 체크를 모두 실행해야 함 — scan secrets 등 보안 step 이 리팩터로 조용히 빠지면 가드레일 무력화.
|
|
2934
|
+
const has5 = ["step('verify'", "step('audit'", "step('scan secrets'", "step('encoding check'", "step('lazy detect'"].every(s => body.includes(s));
|
|
2935
|
+
const claims6 = body.includes("step('verify-claims'") && body.includes("has('--claims')");
|
|
2936
|
+
return has5 && claims6;
|
|
2937
|
+
} },
|
|
2928
2938
|
{ name: 'honesty-check: AI 인식론적 정직성 3차원 + MCP/CLI/strict 통합 (사용자명시 1.9.305)', run: () => { const h = _epistemicHonestyCheck; const d1 = h('이 기능은 항상 정상 동작합니다').findings.some(f => f.dim === 'pretend-knowledge'); const d2 = h('아마 될 것 같습니다. 구현 완료했습니다').findings.some(f => f.dim === 'premature-judgment'); const d3 = h('이 API 의 rate limit 은 초당 5회입니다').findings.some(f => f.dim === 'no-info-gathering'); const clean = h('src/api.js 수정, 12/12 통과 (Exit: 0)').ok === true; const src = read(__filename); const wired = require('../lib/mcp-tools').some(t => t.name === 'leerness_honesty_check') && /if \(cmd === 'honesty-check'\)/.test(src) && /honestyFindings = _epistemicHonestyCheck/.test(src); return d1 && d2 && d3 && clean && wired; } },
|
|
2929
2939
|
{ name: 'exit code 일관성: fail()→exitCode 1 행위 + unknown 명령 안내 (UR-0045 / CV-5 행위화 1.9.366)', run: () => { if (typeof fail !== 'function') return false; const saved = process.exitCode; const _w = process.stdout.write; let setOk = false; try { process.stdout.write = () => true; process.exitCode = 0; fail('selftest probe'); setOk = process.exitCode === 1; } finally { process.stdout.write = _w; process.exitCode = saved; } const src = read(__filename); const dispatchOk = /알 수 없는 명령: \$\{cmd\}/.test(src); return setOk && dispatchOk; } },
|
|
2930
2940
|
{ name: 'brief: 프로젝트 청사진 set/show/export + README 개요 섹션 (UR-0055 사용자명시 1.9.307)', run: () => { const src = read(__filename); const fnOk = typeof briefCmd === 'function' && typeof _loadBrief === 'function' && typeof _briefBlueprint === 'function' && _BRIEF_FIELDS.length === 10; const b = { project: 'X', intro: 'i', purpose: 'p', problem: '', features: ['f1', 'f2'], stack: ['s'], architecture: '', users: [], success: [], nonGoals: [], currentState: '' }; const bp = _briefBlueprint(b, VERSION); const bpOk = /Blueprint/.test(bp) && /소개 \(Intro\)/.test(bp) && /f1/.test(bp) && /신규 프로젝트 시작 가이드/.test(bp); const rb = _briefReadmeBlock(b); const rbOk = rb.includes(BRIEF_START) && rb.includes(BRIEF_END) && /프로젝트 개요/.test(rb) && /\*\*목적\*\*/.test(rb); return fnOk && bpOk && rbOk && /if \(cmd === 'brief'\)/.test(src); } },
|
package/package.json
CHANGED
package/scripts/e2e.js
CHANGED
|
@@ -6469,6 +6469,31 @@ total++;
|
|
|
6469
6469
|
if (!ok) failed++;
|
|
6470
6470
|
}
|
|
6471
6471
|
|
|
6472
|
+
// 1.35.10 (자체 gate 적대적 헌트): gate 를 "보안 가드레일"로 검증 — 8-프로브 헌트(FP 4 + FN 3 + by-design 1) 결과 제품 결함 0 확인 후, 유일 커버리지 갭(gate 레벨 보안 동작)을 회귀 가드로 고정. 커밋된 실키 → 차단(exit 1, scan secrets step), 정상 .env.example placeholder → 오탐 없이 통과(exit 0). scan-step 리팩터가 가드레일 보안을 조용히 무너뜨리는 회귀 차단.
|
|
6473
|
+
total++;
|
|
6474
|
+
{
|
|
6475
|
+
let ok = false;
|
|
6476
|
+
try {
|
|
6477
|
+
const d = fs.mkdtempSync(path.join(os.tmpdir(), 'leerness-gatesec-'));
|
|
6478
|
+
const R = (a) => cp.spawnSync(process.execPath, [CLI, ...a, '--path', d], { encoding: 'utf8', timeout: 30000 });
|
|
6479
|
+
cp.spawnSync(process.execPath, [CLI, 'init', d, '--yes'], { encoding: 'utf8', timeout: 30000 });
|
|
6480
|
+
cp.spawnSync(process.execPath, [CLI, 'handoff', '', '--path', d], { encoding: 'utf8', timeout: 20000 });
|
|
6481
|
+
// (a) 정상 placeholder(.env.example 교과서) → gate 오탐 없이 통과(exit 0)
|
|
6482
|
+
fs.writeFileSync(path.join(d, '.env.example'), 'DATABASE_URL=postgres://user:password@localhost:5432/db\nAPI_KEY=your-api-key-here\n');
|
|
6483
|
+
const gClean = R(['gate', '.', '--json']);
|
|
6484
|
+
let cleanOk = false; try { const j = JSON.parse(gClean.stdout); cleanOk = gClean.status === 0 && j.ok === true; } catch {}
|
|
6485
|
+
// (b) 커밋된 실 AWS 키(.js) → gate 차단(exit 1) + scan secrets check 실패
|
|
6486
|
+
fs.writeFileSync(path.join(d, 'leak.js'), 'const k = "AKIAJQXMP7RZ2KL9WXYZ";\nmodule.exports = k;\n');
|
|
6487
|
+
const gSecret = R(['gate', '.', '--json']);
|
|
6488
|
+
let secretBlocked = false; try { const j = JSON.parse(gSecret.stdout); const sc = (j.checks || []).find(c => c.name === 'scan secrets'); secretBlocked = gSecret.status === 1 && j.ok === false && sc && sc.ok === false; } catch {}
|
|
6489
|
+
fs.rmSync(d, { recursive: true, force: true });
|
|
6490
|
+
ok = cleanOk && secretBlocked;
|
|
6491
|
+
if (!ok) console.log(` [gatesec 디버그] cleanExit0=${cleanOk} secretBlocked=${secretBlocked}`);
|
|
6492
|
+
} catch (e) {}
|
|
6493
|
+
console.log(ok ? '✓ B(1.35.10) gate 보안 가드레일: 정상 placeholder 오탐 없이 통과(exit 0) + 커밋된 실키 차단(exit 1, scan secrets step)' : '✗ gate 보안 가드레일 가드 실패');
|
|
6494
|
+
if (!ok) failed++;
|
|
6495
|
+
}
|
|
6496
|
+
|
|
6472
6497
|
// 1.9.430 (10th 외부평가 UR-0130): health 보안 CRITICAL(커밋 시크릿)은 --strict 없이도 exit 1(CI 게이트). 클린은 exit 0.
|
|
6473
6498
|
total++;
|
|
6474
6499
|
{
|