leerness 1.35.10 → 1.35.12

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 CHANGED
@@ -1,5 +1,31 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.35.12 — 2026-07-06 — codex 협업 라운드 ②: clean-room 평가 문서 갱신 + codex 정직성 리뷰 8건 반영 (UR-0011)
4
+
5
+ **사용자 지시 "codex와 협업" 라운드 ② — clean-room 평가 문서 갱신.** `docs/clean-room-evaluations.md` 가 1.19.0(selftest 231)에서 멈춰 stale → 이번 세션 자체 적대적 헌트(verify-claim FP/gate/contract)를 추가하고, codex(gpt-5.5 xhigh)를 **정직성 감사관**으로 병렬 실행해 과장 표현을 교정.
6
+
7
+ ### 갱신
8
+ - 평가를 **"에이전트 클린룸 평가"(behavior-only)** 와 **"메인테이너 자체 적대적 헌트"(self-administered, 가장 덜 독립적)** 로 명확히 구분 — 1.35.9/10/11 헌트를 정직 outcome(FP 1건 발견·수정 / 0 product bug / codex 9건 중 3확정·1환각기각)으로 표에 추가. 한계 섹션에 contract heuristic 한계(UR-0018) + scan secrets 포지셔닝 추가.
9
+ - **codex 정직성 리뷰 8건 전부 반영**(협업 검수 결과): "every evaluation"→"most", "real development"→"development exercises", "Independently"→"Separately", "External reviews"→"maintainer-run(external models≠외부 인간)", "Codex independent review"→"separate Codex review", "converged on 0 bugs"→"0 bugs found in these probes", 그리고 핵심 — "reliably catches ... without false-failing"의 **자기모순 교정**(문서 자신이 1.35.9에서 FP를 찾았으므로 "no false failures"는 보장이 아니라 검사 중인 속성이라 명시).
10
+
11
+ ### 검증
12
+ - selftest **271** (기존 clean-room 문서 가드를 정직성 마커 강화: clean-room + heuristic + **self-administered** + 재현 레시피). full e2e (문서-only 변경, 무영향). 문서 변경이라 런타임 동작 불변.
13
+
14
+ ## 1.35.11 — 2026-07-06 — codex 협업 contract verify 적대적 헌트: FP 3종 수정 ($ 필드 정규식 + bracket export + 코드펜스 예제)
15
+
16
+ **사용자 지시 "codex와 협업" 라운드 ① — contract verify 적대적 헌트.** codex(gpt-5.5 xhigh 독립 분석)와 Claude(프로브+맹신X 검수) 병렬로 FN/FP/crash 사냥. codex 9건 제기 → 재현으로 검증: 3건 확정 수정, 3건 by-design/heuristic 한계(백로그), 3건은 이미 수정한 `$` 정규식 계열, 1건은 codex 환각(재현 기각).
17
+
18
+ ### 확정 FP (재현 확인 → 수정)
19
+ - **① 필드명 `$` 정규식-앵커 오탐 (Claude 발견)**: `## Fields` 필드가 `new RegExp(\`\\b${f}\\b\`)` 로 impl 소스에 grep 되는데 JS 식별자에 유효한 `$` 가 **정규식 앵커로 해석**돼 `$scope`/`foo$bar` 실존 필드를 **항상 missing 오탐(exit 1)** → CI 계약이 compliant impl 거짓 차단. `\b` 도 `$`-접두 식별자 앞에서 경계 못 잡음. → 메타문자 이스케이프 + **식별자-경계 룩어라운드**(`(?<![\w$])x(?![\w$])`, Node≥18)로 교체. (함수 검사는 Set 멤버십이라 무관 — `$init` 정상.)
20
+ - **② bracket export 미인식 (codex #8)**: `exports["foo"] = function(){}` 를 `_parseImplExports` 가 dot 표기만 인식해 미노출 → 실존 함수를 누락 오판. bracket 패턴 추가.
21
+ - **③ 코드펜스 예제를 계약으로 오인 (codex #9)**: spec 의 ```` ```js function helper(){} ``` ```` 예제가 `_parseContractSpec` 에서 declared 로 잡혀 impl 에 helper 강제 → 예제 있는 정상 spec 거짓 차단. triple-backtick 블록 제거 후 선언/필드 추출.
22
+
23
+ ### 백로그 (heuristic 한계/by-design — 수정 안 함, UR-0016 AST)
24
+ - 필드/함수가 주석·문자열에만 존재 → grep 통과(FN, codex #1): grep-presence 검사의 문서화된 한계. 함수를 stub/비함수값으로 export → 통과(codex #6): contract 는 presence, verify-claim 이 substance(설계상 분리). backtick 약언급 미게이팅(codex #5): 산문 FP 회피 위한 의도적 관대. codex #7(ESM export-list)는 **재현서 이미 인식됨을 확인 → 환각 기각**. 세 수정 모두 위 한계를 악화시키지 않음.
25
+
26
+ ### 검증
27
+ - selftest **271** (신규: `_parseImplExports` bracket + `_parseContractSpec` 펜스제외 순수함수 행위검사; 자기참조 트랩 회피 위해 소스-grep→행위검사 전환). full e2e **384** (신규: $필드 실존→통과/진짜누락→감지 + bracket #8 + 펜스 #9 FP 3종). codex 독립 헌트 교차확인(맹신 X: 9건 중 3 확정·1 환각기각·나머지 한계).
28
+
3
29
  ## 1.35.10 — 2026-07-06 — 자체 gate 적대적 헌트: 가드레일 검증(제품 결함 0) + 보안 동작 회귀 가드
4
30
 
5
31
  **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) 실행.
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.10 하네스를 사용합니다. AI 에이전트는 작업 전 `leerness handoff`로 컨텍스트를 적재하고, 작업 후 `leerness check`/`leerness audit`/`leerness session close`를 수행해야 합니다.
128
+ 이 프로젝트는 Leerness v1.35.12 하네스를 사용합니다. 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.10는 stdio JSON-RPC MCP server를 내장합니다 — Claude Code · Cursor · Codex CLI 등 외부 AI에 **86개 도구**를 노출:
182
+ Leerness v1.35.12는 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.10는 stdio JSON-RPC MCP server를 내장합니다 — Claude Cod
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.10)** · 매 라운드 GitHub release/태그 생성 · _reports/는 비공개 보존.
203
+ 현재 누적: **70 라운드 (1.9.40 → 1.35.12)** · 매 라운드 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.10: 2026-07-06
241
+ Last synced by Leerness v1.35.12: 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.10';
35
+ const VERSION = '1.35.12';
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') 시 호스트 프로세스 오염.
@@ -2935,6 +2935,14 @@ function _selfTestCases() {
2935
2935
  const claims6 = body.includes("step('verify-claims'") && body.includes("has('--claims')");
2936
2936
  return has5 && claims6;
2937
2937
  } },
2938
+ { name: '자체 contract 적대적 헌트 + codex 교차 (1.35.11): _parseImplExports bracket(#8) + _parseContractSpec 코드펜스 예제 제외(#9) — FP 2종 행위검사($ 필드 FP는 e2e cvdollar 담당)', run: () => {
2939
+ const p = require('../lib/pure-utils');
2940
+ const bracket = p._parseImplExports('exports["foo"] = function(){};\n').includes('foo'); // #8: bracket export 인식
2941
+ const dotStill = p._parseImplExports('exports.bar = 1;\n').includes('bar'); // 회귀: dot 유지
2942
+ const fenceExcluded = !p._parseContractSpec('# S\n```js\nfunction helper(){}\n```\n').declared.includes('helper'); // #9: 펜스 예제 제외
2943
+ const realDecl = p._parseContractSpec('function realFn(){}\n').declared.includes('realFn'); // 회귀: 펜스 밖 선언 유지
2944
+ return bracket && dotStill && fenceExcluded && realDecl;
2945
+ } },
2938
2946
  { 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; } },
2939
2947
  { 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; } },
2940
2948
  { 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); } },
@@ -3815,11 +3823,12 @@ function _selfTestCases() {
3815
3823
  && eq(F([]), [])
3816
3824
  && eq(F(['a.css', 'b.md', 'c.js', 'd.test.js']).length, 2); // 최대 2개 클러터 방지
3817
3825
  } },
3818
- { name: 'GPT-5.5 평가 #5 (1.19.1, UR-0009): 클린룸 평가 문서 공개 + 한계 명시 (행위)', run: () => {
3826
+ { name: 'GPT-5.5 평가 #5 (1.19.1, UR-0009) + 정직성 calibration (1.35.12): 클린룸 문서 공개 + 한계 명시 + self-administered 라벨 (행위)', run: () => {
3819
3827
  const dp = path.join(path.dirname(__filename), '..', 'docs', 'clean-room-evaluations.md');
3820
3828
  if (!exists(dp)) return true; // 패키지에 없으면 스킵(설치본 안전)
3821
3829
  const d = read(dp);
3822
- return /AI clean-room evaluations/i.test(d) && /heuristic, not semantic/i.test(d) && /npm i leerness@/.test(d);
3830
+ // 1.35.12: 정직성 마커 강화 — clean-room 프레이밍 + heuristic 한계 + self-administered(독립 아님) + 재현 레시피.
3831
+ return /clean-room/i.test(d) && /heuristic, not semantic/i.test(d) && /self-administered/i.test(d) && /npm i leerness@/.test(d);
3823
3832
  } },
3824
3833
  { name: 'CLI 영어화 Phase 1 (1.20.2, UR-0010): _uiLang 해석(flag>env>manifest>ko) + 첫화면 _t 적용 (행위+소스)', run: () => {
3825
3834
  const save = process.argv; const saveEnv = process.env.LEERNESS_LANG;
@@ -19676,7 +19685,11 @@ function contractVerifyCmd(specPath, implPath) {
19676
19685
  }
19677
19686
  const fieldMissing = [];
19678
19687
  for (const f of fieldSpec) {
19679
- if (!new RegExp(`\\b${f}\\b`).test(implSrc)) fieldMissing.push(f);
19688
+ // 1.35.11 (자체 contract 적대적 헌트 + codex 교차): 필드명을 raw 로 RegExp 에 넣던 FP 수정.
19689
+ // 식별자에 유효한 `$` 가 정규식에서 앵커로 해석돼 `$scope`/`foo$bar` 같은 실존 필드를 항상 missing 오탐(exit 1) → CI 계약이 compliant impl 을 거짓 차단.
19690
+ // 또 \b 는 비단어문자(`$`)-접두 식별자 앞에서 경계를 못 잡음. → 메타문자 이스케이프 + 식별자-경계 룩어라운드로 교체(Node≥18 lookbehind). 함수 검사는 Set 멤버십이라 무관.
19691
+ const _fe = f.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
19692
+ if (!new RegExp(`(?<![\\w$])${_fe}(?![\\w$])`).test(implSrc)) fieldMissing.push(f);
19680
19693
  }
19681
19694
  // 출력
19682
19695
  if (has('--json')) {
@@ -1,67 +1,96 @@
1
- # Clean-room evaluations / 클린룸 평가 기록
2
-
3
- > **What this is, honestly.** These are **AI clean-room evaluations** — independent agents installing the
4
- > published npm package into fresh temp directories and exercising it from behavior only (no access to the
5
- > source tree), including adversarial attempts to defeat leerness's own verifier. They are **not**
6
- > third-party human security audits or peer-reviewed benchmarks. We publish them so the README claim
7
- > "verified by independent clean-room evaluations" is checkable rather than a marketing line.
8
- >
9
- > 정직하게 말하면: 아래는 **AI 클린룸 평가**입니다 독립 에이전트가 게시된 npm 패키지를 임시 폴더에
10
- > 설치해 **소스 접근 없이 행위만으로** 검증하고, leerness 검증기 자체를 무력화하려는 적대 시도까지 포함합니다.
11
- > 제3자 인간 보안 감사나 동료심사 벤치마크가 **아닙니다**. README "독립 클린룸 평가로 검증" 주장을
12
- > 확인 가능하게 만들기 위해 공개합니다.
13
-
14
- ## Methodology / 방법론
15
-
16
- Every evaluation follows the same shape:
17
-
18
- ```bash
19
- W=$(mktemp -d); cd "$W"; npm init -y
20
- npm i leerness@<version> # the PUBLISHED package, not the working tree
21
- LB="node node_modules/leerness/bin/leerness.js"
22
- # ... drive the CLI by behavior, assert on exit codes + output, clean up ...
23
- ```
24
-
25
- - **Published-artifact only** installs from npm, never reads the repo source. This is what an external user gets.
26
- - **Behavior-asserted** — checks process exit codes and stdout/stderr, not internal state.
27
- - **Adversarial** — a portion of every pass actively tries to make a *false* "done" claim pass verification
28
- (comment-only stubs, empty-export shells, `assert(true)` fake tests, inflated test counts, language tricks).
29
- - **Both directions (맹신 X / "trust nothing")** — confirmed real defects AND rejected false alarms; a finding
30
- counts only if reproduced on the published package.
31
-
32
- ## Evaluations run / 수행한 평가
33
-
34
- | # | Round | Scope | Outcome |
35
- |---|---|---|---|
36
- | 1 | Universal-harness field study (5-axis) | Real Python / Node / Rust development, agent-swap handoff, adversarial attack on the verifier | Verdict "conditionally yes"; found 5 gaps (2×P1, 3×P2) — all closed in 1.17.2–1.17.6, shipped as the 1.18.0 stable minor |
37
- | 2 | 1.18.0 re-verification (published) | Independently re-ran the 5 gaps against the **published** 1.18.0 | 4 closed; surfaced a new P1 (Windows `--test-cmd python` blocked → false FAIL) → fixed in 1.18.1 |
38
- | 3 | 1.18.2 adversarial stub workflow | Bypass-hunters + false-positive-hunters vs the empty-shell stub detector | 9 one-keyword bypasses found (Object.freeze, async fn, inline comment, …) and closed; **0 false positives** across ~45 legitimate patterns |
39
- | 4 | 1.19.0 published-artifact re-verification | Installed `leerness@1.19.0` from npm; smoke-tested headline fixes | `--test-cmd python`, empty-shell rejection, `lens`, selftest 231 — all pass on the published package |
40
-
41
- ## What these evaluations do NOT establish / 한계 (정직)
42
-
43
- leerness's verification is **heuristic, not semantic**. These evaluations show it reliably catches *obvious
44
- false-done claims* (missing files, empty shells, fake/unlinked tests, inflated counts) without false-failing
45
- honest work. They do **not** prove:
46
-
47
- - the implementation satisfies the actual requirement, or business logic is correct;
48
- - tests are sufficient or well-designed;
49
- - absence of security vulnerabilities or production-runtime correctness.
50
-
51
- Known heuristic gaps tracked for an AST/token-based redesign: multi-arg call-expression empty objects
52
- (`Object.assign({}, {})`), Python `def …: pass` / `...` / `raise NotImplementedError`, multi-language empty
53
- bodies. **Code coverage / mutation testing and third-party reproduction remain open** (the e2e is a
54
- spawn-based runner, which standard coverage tools do not instrument cleanly).
55
-
56
- ## Reproduce it yourself / 직접 재현
57
-
58
- ```bash
59
- W=$(mktemp -d); cd "$W"; npm init -y && npm i leerness@latest
60
- LB="node node_modules/leerness/bin/leerness.js"
61
- $LB init "$W" --yes
62
- # fake "done": claim an implementation that does not exist
63
- $LB task add "Implement X"
64
- $LB task update T-0001 --status done --evidence "x.js done, 5 tests passed"
65
- $LB verify-claim T-0001 # exit 1 claim rejected (x.js missing, no tests ran)
66
- $LB selftest # core-function integrity self-check
67
- ```
1
+ # Clean-room evaluations / 클린룸 평가 기록
2
+
3
+ > **What this is, honestly.** These are **AI evaluations run by the project itself** — an agent installs the
4
+ > published npm package into fresh temp directories and exercises it from behavior only (no access to the
5
+ > source tree), including adversarial attempts to defeat leerness's own verifier. They are **self-administered**
6
+ > (the maintainer's AI, sometimes cross-checked by a second model such as Codex), **not** third-party human
7
+ > security audits or peer-reviewed benchmarks, and **not** independent in the "unaffiliated reviewer" sense.
8
+ > We publish them so the README claim "checkable by clean-room evaluation" is verifiable rather than a
9
+ > marketing lineyou can re-run the recipe below yourself.
10
+ >
11
+ > 정직하게 말하면: 아래는 **프로젝트가 직접 수행한 AI 평가**입니다 에이전트가 게시된 npm 패키지를 빈 임시
12
+ > 폴더에 설치해 **소스 접근 없이 행위만으로** 검증하고, leerness 검증기 자체를 무력화하려는 적대 시도까지
13
+ > 포함합니다. 이는 **자기-수행**(메인테이너의 AI, 때때로 Codex 같은 2차 모델이 교차검증)이며, 제3자 인간 보안
14
+ > 감사·동료심사 벤치마크가 **아니고**, "무관한 외부 리뷰어"라는 의미의 독립도 **아닙니다**. README 의 "클린룸
15
+ > 평가로 확인 가능" 주장을 검증 가능하게 만들기 위해 공개하며, 아래 레시피로 직접 재현할 수 있습니다.
16
+
17
+ ## Methodology / 방법론
18
+
19
+ Most evaluations follow this general shape:
20
+
21
+ ```bash
22
+ W=$(mktemp -d); cd "$W"; npm init -y
23
+ npm i leerness@<version> # the PUBLISHED package, not the working tree
24
+ LB="node node_modules/leerness/bin/leerness.js"
25
+ # ... drive the CLI by behavior, assert on exit codes + output, clean up ...
26
+ ```
27
+
28
+ - **Published-artifact only** installs from npm, never reads the repo source. This is what an external user gets.
29
+ - **Behavior-asserted** — checks process exit codes and stdout/stderr, not internal state.
30
+ - **Adversarial (both directions)** many passes include attempts to make a *false* "done" claim pass
31
+ verification (comment-only stubs, empty-export shells, `assert(true)` fake tests, inflated test counts) **and**
32
+ to make an *honest* claim wrongly fail (false-positive hunting). A finding counts only if reproduced on the
33
+ published package; agent-proposed findings are re-derived, not trusted (맹신 X / "trust nothing").
34
+
35
+ ## Agent clean-room evaluations / 에이전트 클린룸 평가 (behavior-only, published artifact)
36
+
37
+ | # | Round | Scope | Outcome |
38
+ |---|---|---|---|
39
+ | 1 | Universal-harness field study (5-axis) | Python / Node / Rust development exercises, agent-swap handoff, adversarial attack on the verifier | Verdict "conditionally yes"; found 5 gaps (2×P1, 3×P2) — all closed in 1.17.2–1.17.6, shipped as the 1.18.0 stable minor |
40
+ | 2 | 1.18.0 re-verification (published) | Separately re-ran the 5 gaps against the **published** 1.18.0 | 4 closed; surfaced a new P1 (Windows `--test-cmd python` blocked → false FAIL) → fixed in 1.18.1 |
41
+ | 3 | 1.18.2 adversarial stub workflow | Bypass-hunters + false-positive-hunters vs the empty-shell stub detector | 9 one-keyword bypasses found (Object.freeze, async fn, inline comment, …) and closed; **0 false positives** across ~45 legitimate patterns |
42
+ | 4 | 1.19.0 published-artifact re-verification | Installed `leerness@1.19.0` from npm; smoke-tested headline fixes | `--test-cmd python`, empty-shell rejection, `lens`, selftest — all pass on the published package |
43
+
44
+ Maintainer-run multi-model reviews (external models GPT-class + Claude driven against a published build and
45
+ reproduced before fixing) have also shaped many rounds; the confirmed findings are tracked in CHANGELOG under
46
+ the "Nth 외부평가 / 외부리뷰" entries. "External" here means the *models*, not unaffiliated human reviewers.
47
+
48
+ ## Maintainer adversarial hunts / 메인테이너 자체 적대적 헌트 (self-administered, published artifact)
49
+
50
+ These are the **least independent** kind — the maintainer's AI hunting its own flagship surfaces, cross-checked
51
+ with Codex where noted. They are listed for transparency, not as third-party validation. Every finding was
52
+ reproduced on the published package; every fix re-verified after publish.
53
+
54
+ | Version | Surface | Method | Outcome (honest) |
55
+ |---|---|---|---|
56
+ | 1.35.9 | `verify-claim` declared-pass gate | 12-probe FP/FN matrix (single / `--json` / `--all` / `gate --claims` × reporter/growth/lenient) | 1 real false-positive found (a non-test `N/M passing` ratio wrongly gated) and fixed; 0 bypasses |
57
+ | 1.35.10 | `gate` (the CI guardrail) | 8-probe matrix (clean/placeholder/secret/false-done/missing-file) | **0 product bugs**; 2 probe-flagged "FN"s were probe artifacts, refuted by reproduction; added a gate-level security regression guard |
58
+ | 1.35.11 | `contract verify` (spec ↔ impl) | Claude probes + a separate Codex (gpt-5.5) review, cross-checked | Codex raised 9 candidates → **3 confirmed & fixed** (`$`-field regex FP, bracket-export FP, code-fence-example FP), **1 refuted as a hallucination**, the rest documented heuristic limits |
59
+
60
+ The pattern worth noting: two of the three surfaces had **0 product bugs found in these probes** only after a
61
+ dedicated false-positive hunt, and in each round a portion of the AI-proposed findings did **not** reproduce and
62
+ were dropped. That is the point of publishing this — the checks are fallible, the probe matrices are finite, and
63
+ the checks are themselves under adversarial test, including their own false-alarm behavior.
64
+
65
+ ## What these evaluations do NOT establish / 한계 (정직)
66
+
67
+ leerness's verification is **heuristic, not semantic**. These evaluations suggest it catches many *obvious
68
+ false-done claims* (missing files, empty shells, fake/unlinked tests, inflated counts), with no false failures
69
+ in the tested cases — though the false-positive hunts have themselves found and fixed a real false-positive
70
+ (1.35.9), so "no false failures" is a property under test, not a guarantee. They do **not** prove:
71
+
72
+ - the implementation satisfies the actual requirement, or business logic is correct;
73
+ - tests are sufficient or well-designed;
74
+ - absence of security vulnerabilities or production-runtime correctness.
75
+
76
+ Known heuristic gaps tracked for an AST/token-based redesign (UR-0016): multi-arg call-expression empty objects
77
+ (`Object.assign({}, {})`), Python `def …: pass` / `...` / `raise NotImplementedError`, multi-language empty
78
+ bodies; and for `contract verify` (UR-0018) a field/function present only in a **comment or string** still
79
+ passes the grep-presence check, and a function exported as a **non-function value** passes (contract checks
80
+ *presence*; `verify-claim` checks *substance* — a deliberate split). `scan secrets` is a convenience guard, not
81
+ a replacement for a dedicated scanner (gitleaks/trufflehog). **Code coverage / mutation testing and third-party
82
+ reproduction remain open** (the e2e is a spawn-based runner, which standard coverage tools do not instrument
83
+ cleanly).
84
+
85
+ ## Reproduce it yourself / 직접 재현
86
+
87
+ ```bash
88
+ W=$(mktemp -d); cd "$W"; npm init -y && npm i leerness@latest
89
+ LB="node node_modules/leerness/bin/leerness.js"
90
+ $LB init "$W" --yes
91
+ # fake "done": claim an implementation that does not exist
92
+ $LB task add "Implement X"
93
+ $LB task update T-0001 --status done --evidence "x.js done, 5 tests passed"
94
+ $LB verify-claim T-0001 # exit 1 — claim rejected (x.js missing, no tests ran)
95
+ $LB selftest # core-function integrity self-check (exit 0 when the install is intact)
96
+ ```
package/lib/pure-utils.js CHANGED
@@ -953,6 +953,8 @@ function _parseImplExports(src) {
953
953
  }
954
954
  // 2) exports.foo = / module.exports.foo =
955
955
  for (const m of src.matchAll(/(?:module\.)?exports\.([A-Za-z_$][\w$]*)\s*=/g)) add(m[1]);
956
+ // 2b) 1.35.11 (codex 교차 헌트 #8): bracket 표기 exports["foo"] / module.exports['foo'] = ... — 종전 dot 표기만 인식해 bracket export 를 미노출(FP: contract 가 실존 함수를 누락으로 오판).
957
+ for (const m of src.matchAll(/(?:module\.)?exports\s*\[\s*['"]([A-Za-z_$][\w$]*)['"]\s*\]\s*=/g)) add(m[1]);
956
958
  // 3) ESM 선언: export [async] function*/const/let/var/class foo
957
959
  for (const m of src.matchAll(/export\s+(?:async\s+)?(?:function\s*\*?|const|let|var|class)\s+([A-Za-z_$][\w$]*)/g)) add(m[1]);
958
960
  // 4) ESM 목록/재export: export { foo, bar as baz } / export { default as X } from './m' → 외부이름(as 뒤) 우선.
@@ -1165,7 +1167,9 @@ function _migrationGuideText(version) {
1165
1167
  // mentioned(약언급, 표시만): backtick `name(` — 산문 인라인 언급일 수 있어 누락검사 제외(기존 관대성 유지).
1166
1168
  // fields: tick.name. bullet 패턴은 name 직후 '(' (공백 불허) → 산문 "- 합 (a+b)" 오탐 방지, ASCII 식별자만.
1167
1169
  function _parseContractSpec(specText) {
1168
- const s = specText || '';
1170
+ // 1.35.11 (codex 교차 헌트 #9): 코드펜스(```...```) 안 예제 코드를 계약으로 오인하던 FP — 예: spec 의 ```js function helper(){} ``` 가 declared 로 잡혀 impl 에 helper 강제.
1171
+ // 모든 선언/필드 추출은 펜스 제거본(펜스→개행 치환, 줄 구조 보존)에서 수행. 인라인 single-backtick 은 미영향(triple-backtick 블록만 제거).
1172
+ const s = (specText || '').replace(/```[\s\S]*?```/g, '\n');
1169
1173
  const declared = new Set();
1170
1174
  const mentioned = new Set();
1171
1175
  const fields = new Set();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "leerness",
3
- "version": "1.35.10",
3
+ "version": "1.35.12",
4
4
  "description": "Leerness: 비파괴 마이그레이션, 자동 버전 감지·업데이트, 계획/진행/핸드오프 자동화, 게으름·시크릿·인코딩 자동 가드, Claude Code 슬래시 통합을 갖춘 한국어 우선 AI 개발 하네스.",
5
5
  "keywords": [
6
6
  "leerness",
package/scripts/e2e.js CHANGED
@@ -6016,6 +6016,40 @@ total++;
6016
6016
  if (!ok) failed++;
6017
6017
  }
6018
6018
 
6019
+ // 1.35.11 (자체 contract 적대적 헌트 + codex 교차): 필드명 $ 정규식-앵커 FP — $scope/foo$bar 실존 필드를 항상 missing 오탐하던 버그. 이스케이프+식별자 룩어라운드로 수정. 정규식 안전 + no-FN 회귀 가드.
6020
+ total++;
6021
+ {
6022
+ let ok = false;
6023
+ try {
6024
+ const d = fs.mkdtempSync(path.join(os.tmpdir(), 'leerness-cvdollar-'));
6025
+ cp.spawnSync(process.execPath, [CLI, 'init', d, '--yes', '--language', 'ko'], { encoding: 'utf8', timeout: 30000 });
6026
+ fs.writeFileSync(path.join(d, 's.md'), '# S\n\n## Fields\n- $scope\n- foo$bar\n- userId\n');
6027
+ // (1) FP 수정: $scope/foo$bar/userId 모두 impl 에 실존 → 통과(exit 0, missingFields 0)
6028
+ fs.writeFileSync(path.join(d, 'ok.js'), 'const $scope=1; const foo$bar=2; const userId=3;\nmodule.exports={$scope,foo$bar,userId};\n');
6029
+ const cok = cp.spawnSync(process.execPath, [CLI, 'contract', 'verify', path.join(d, 's.md'), path.join(d, 'ok.js'), '--json'], { encoding: 'utf8', timeout: 15000 });
6030
+ let fpFixed = false; try { const j = JSON.parse(cok.stdout); fpFixed = cok.status === 0 && j.ok === true && (j.missingFields || []).length === 0; } catch {}
6031
+ // (2) no-FN 회귀: $scope 진짜 누락 → 여전히 감지(exit 1, missingFields 에 $scope)
6032
+ fs.writeFileSync(path.join(d, 'miss.js'), 'const foo$bar=2; const userId=3;\nmodule.exports={foo$bar,userId};\n');
6033
+ const cmiss = cp.spawnSync(process.execPath, [CLI, 'contract', 'verify', path.join(d, 's.md'), path.join(d, 'miss.js'), '--json'], { encoding: 'utf8', timeout: 15000 });
6034
+ let fnGuard = false; try { const j = JSON.parse(cmiss.stdout); fnGuard = cmiss.status === 1 && j.ok === false && (j.missingFields || []).includes('$scope') && !(j.missingFields || []).includes('foo$bar'); } catch {}
6035
+ // (3) codex #8: bracket export(exports["foo"]) 실존 → 통과(exit 0)
6036
+ fs.writeFileSync(path.join(d, 'b.md'), '- foo()\n');
6037
+ fs.writeFileSync(path.join(d, 'b.js'), 'exports["foo"] = function(){};\n');
6038
+ const cbrk = cp.spawnSync(process.execPath, [CLI, 'contract', 'verify', path.join(d, 'b.md'), path.join(d, 'b.js'), '--json'], { encoding: 'utf8', timeout: 15000 });
6039
+ let bracketOk = false; try { const j = JSON.parse(cbrk.stdout); bracketOk = cbrk.status === 0 && j.ok === true; } catch {}
6040
+ // (4) codex #9: 코드펜스 예제 함수는 계약 아님 → 통과(exit 0) + specFunctions 에 helper 없음
6041
+ fs.writeFileSync(path.join(d, 'fen.md'), '# S\n```js\nfunction helper(){}\n```\n');
6042
+ fs.writeFileSync(path.join(d, 'fen.js'), 'module.exports={};\n');
6043
+ const cfen = cp.spawnSync(process.execPath, [CLI, 'contract', 'verify', path.join(d, 'fen.md'), path.join(d, 'fen.js'), '--json'], { encoding: 'utf8', timeout: 15000 });
6044
+ let fenceOk = false; try { const j = JSON.parse(cfen.stdout); fenceOk = cfen.status === 0 && j.ok === true && !(j.specFunctions || []).includes('helper'); } catch {}
6045
+ fs.rmSync(d, { recursive: true, force: true });
6046
+ ok = fpFixed && fnGuard && bracketOk && fenceOk;
6047
+ if (!ok) console.log(` [cvdollar 디버그] fpFixed=${fpFixed} fnGuard=${fnGuard} bracket=${bracketOk} fence=${fenceOk}`);
6048
+ } catch {}
6049
+ console.log(ok ? '✓ B(1.35.11) 자체 contract 헌트 + codex 교차: $필드 정규식 안전화 + bracket export(#8) + 코드펜스 예제 제외(#9) FP 3종 + no-FN' : '✗ contract 헌트 FP 3종 수정 실패');
6050
+ if (!ok) failed++;
6051
+ }
6052
+
6019
6053
  // 1.9.418 회귀 (9th 외부평가 Codex P2, UR-0121 잔여): health 보안 정직화 + status scope
6020
6054
  total++;
6021
6055
  {