leerness 1.36.60 → 1.36.61

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,15 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.36.61 — 2026-07-21 — .harness 정책·시드 문서군 en 완역 (F-05 3회차) — R-0001 검수 6회전
4
+
5
+ en init 한글 잔존 53/61 → **23/61** (1·3회차 누적). 검수 계약 대조: 6개 대표 문서 규칙 전량 보존 확인.
6
+
7
+ - **en 오버라이드 27종**: guideline/guardrails/anti-lazy/writeback/session-close/secret/encoding/consistency/testing/checklists/plan·brief·current-state·decisions·task-log·handoff 시드 등 — read-order 참조층 전체.
8
+ - **자가 선검**: en brief placeholder 문구가 감지 regex 와 미스매치(작성됨 오판) → 문구 정합 (anchors status true/true 실측).
9
+ - (검수 High) **정책문서 12종 managed 편입** — 언어 전환 시 구 언어로 방치되던 것 (사용자 상태 문서는 의도 제외). 실측: en→ko 전환 시 guardrails 한국어 재생성 + 커스텀 1회 + 영어 잔재 0.
10
+ - (검수 Medium) **en 센티널 인식**: audit/lazy detect 의 `(자동)`, design-token `(실제 값으로 업데이트)` 만 알던 감시자들에 `(auto)`/`(update with real value)` 병기 — KO/EN audit 발견 동수(5=5) 회복, --fix 양 언어.
11
+ - 검증: e2e en 케이스 10종 무한글로 확대, selftest 332, 검수 통과 프로브(파서 소비자 전수·integrity en 12종·전환 왕복).
12
+
3
13
  ## 1.36.60 — 2026-07-21 — 언어 전환 현지화 병합 (F-05 2회차, 전 검수 High 해소) — R-0001 검수 5회전
4
14
 
5
15
  KO→EN(역방향 포함) 전환 시 지시 레이어가 새 언어로 재생성되고 사용자 커스텀만 정확히 1회 이월된다.
package/README.md CHANGED
@@ -122,7 +122,7 @@ MIT
122
122
  <!-- leerness:project-readme:start -->
123
123
  ## Leerness Project Harness
124
124
 
125
- 이 프로젝트는 Leerness v1.36.60 하네스를 사용합니다. AI 에이전트는 작업 전 `leerness handoff`로 컨텍스트를 적재하고, 작업 후 `leerness check`/`leerness audit`/`leerness session close`를 수행해야 합니다.
125
+ 이 프로젝트는 Leerness v1.36.61 하네스를 사용합니다. AI 에이전트는 작업 전 `leerness handoff`로 컨텍스트를 적재하고, 작업 후 `leerness check`/`leerness audit`/`leerness session close`를 수행해야 합니다.
126
126
 
127
127
  ### 정체성 — AI 에이전트 운영 레이어 (UR-0030)
128
128
 
@@ -176,7 +176,7 @@ leerness memory restore decision <date|title>
176
176
 
177
177
  ### MCP server (외부 AI 통합)
178
178
 
179
- Leerness v1.36.60는 stdio JSON-RPC MCP server를 내장합니다 — Claude Code · Cursor · Codex CLI 등 외부 AI에 **86개 도구**를 노출:
179
+ Leerness v1.36.61는 stdio JSON-RPC MCP server를 내장합니다 — Claude Code · Cursor · Codex CLI 등 외부 AI에 **86개 도구**를 노출:
180
180
 
181
181
  ```jsonc
182
182
  // 카테고리별
@@ -197,7 +197,7 @@ Leerness v1.36.60는 stdio JSON-RPC MCP server를 내장합니다 — Claude Cod
197
197
  `<<autonomous-loop-dynamic>>` 신호만 보내면 AI가:
198
198
  1) 다음 라운드 후보 선정 → 2) 코드 변경 → 3) 회귀 테스트 갱신 → 4) 전체 e2e 스위트 통과 → 5) npm publish + git tag → 6) main push → 7) session close → 8) 다음 라운드 예약.
199
199
 
200
- 현재 누적: **v1.9.x → 1.36.60 릴리스 태그 이력** (수백 라운드) · _reports/는 비공개 보존.
200
+ 현재 누적: **v1.9.x → 1.36.61 릴리스 태그 이력** (수백 라운드) · _reports/는 비공개 보존.
201
201
 
202
202
  ### 성능 가이드
203
203
 
@@ -235,6 +235,6 @@ leerness release pack --close --auto-main-push
235
235
  - `.harness/session-handoff.md`: 다음 세션 인수인계 (자동 작성)
236
236
  - `.harness/lessons.md` / `decisions.md` / `rules.md`: 영구 메모리 (5 surface)
237
237
 
238
- Last synced by Leerness v1.36.60: 2026-07-22
238
+ Last synced by Leerness v1.36.61: 2026-07-22
239
239
  <!-- leerness:project-readme:end -->
240
240
 
package/bin/leerness.js CHANGED
@@ -34,7 +34,7 @@ const { CAPABILITY_SURFACE, POWERFUL_COMMANDS, ADAPTERS, REUSE_CATEGORIES, REUSE
34
34
  const { tokenizeForRank: _tokenizeForRank, expandQuery: _expandQuery, scoreHits: _scoreHits, suggestTerms: _suggestTerms } = require('../lib/search-core'); // 1.36.23: memory search 랭킹 코어(순수·0-deps)
35
35
  const { findCorruptedStateJson: _findCorruptedStateJson } = require('../lib/state-integrity'); // 1.36.1 (클린룸 리뷰 FN): .harness/*.json 상태 무결성 (audit/health/check 공유)
36
36
 
37
- const VERSION = '1.36.60';
37
+ const VERSION = '1.36.61';
38
38
 
39
39
  // 1.9.290 (UR-0037, Codex gpt-5.5 #4 수렴): CLI 전용 부작용은 require 시 실행하지 않는다.
40
40
  // 이전: warning listener 제거 / NODE_OPTIONS 변경 / chcp IIFE 가 top-level 즉시 실행 → require('harness') 시 호스트 프로세스 오염.
@@ -667,6 +667,34 @@ leerness memory restore <surface> <target> # archive → active 복귀 (DELETE
667
667
  if (lang === 'en') {
668
668
  _files['AGENTS.md'] = `${MARK}\n# Leerness Agent Instructions\n\n## ⭐ First action every session\n**Read \`.harness/session-workflow.md\` first and follow its 6-step workflow**: analyze request → plan → distribute → sub-agent work → integrated verification → close. Keep the same flow regardless of round length/complexity — that is what prevents drift.\n\n## Static vs dynamic — the leerness boundary\n**AGENTS.md = static project instructions** (coding rules, test commands, prohibitions, deploy steps — rarely change).\n**leerness = dynamic work state, memory, verification, handoff** (current goal, changed files, failed attempts, verification results, next-agent handoff — change every task).\n- Put rules/commands/prohibitions here in AGENTS.md.\n- Dynamic state (decisions/lessons/plan/progress/verification/handoff) is recorded by leerness in the **default workspace \`.harness/\`** (decisions.md / lessons.md / plan.md / progress-tracker.md / session-handoff.md) via \`leerness handoff\`, \`decision add\`, \`lesson save\`, etc.\n- (Optional) the JSON state substrate of \`leerness state show|start|record|verify|handoff\` (or MCP \`leerness_state_*\`) lives in \`.leerness/\` — the cross-agent handoff standard, separate from the main workspace.\n- leerness **complements** AGENTS.md, it does not replace it. Static instructions here, dynamic state in leerness.\n\n## Mandatory read order (session start)\n1. **.harness/session-workflow.md** (6-step workflow — highest priority)\n2. .harness/context-routing.md\n3. .harness/session-handoff.md\n4. .harness/current-state.md\n5. .harness/plan.md\n6. .harness/progress-tracker.md\n7. .harness/guideline.md\n8. .harness/protected-files.md\n9. .harness/writeback-policy.md\n10. .harness/anti-lazy-work-policy.md\n11. **.harness/rules.md** (user-defined standing rules — follow every session)\n\n## Required behavior\n- Run \`leerness handoff .\` at session start to load context (handoff prints active rules automatically).\n- **Ask-on-ambiguity duty**: if the user's request has parts open to interpretation (vague qualifiers, pronouns, multiple alternatives, unclear scope), **ask the user instead of guessing**. Ask the questions produced by \`leerness clarify "<request>"\` verbatim. Even without detected signals, when your own judgment is split, asking wins.\n- **Preview-approval duty (new features)**: when the user asks for a new feature, **do not write code first**. ① Register a preview with \`leerness preview add "<feature>" --design "<design/UX>" --features "<list>"\`, ② present it and ask for approval or revisions, ③ on approval run \`leerness preview approve <P-ID>\`; on revision \`leerness preview revise <P-ID> --note "..."\` and re-present. **Never write the feature's code before approve.**\n- Classify work with \`leerness route <task-type>\` (planning, feature, bugfix, refactor, research, consistency, release, migration, session-start, session-close, harness-maintenance).\n- Never delete protected files/managed sections — merge, archive, or mark deprecated instead.\n- After meaningful changes update progress-tracker, current-state, task-log, session-handoff.\n- Before claiming completion, self-verify with \`leerness check .\` or \`leerness lazy detect .\` and answer the \`leerness lens\` self-questions per domain (code: "would a senior developer find this needlessly complex?" / design: "would a senior designer and an ordinary user find this pretty and intuitive?").\n- Before changes run the guards: \`leerness scan secrets .\`, \`leerness encoding check .\`.\n- Before duplicating a capability check design-system.md, consistency-policy.md, reuse-map.md.\n- Close every session with \`leerness session close .\` — 9 categories (done/in-progress/incomplete/planned/waiting/on-hold/blocked/dropped/verification) + active-rule verification.\n- Updates: \`leerness update --check\` (detect) → \`leerness update --yes\` (auto-migrate).\n\n## Natural-language retro/insights/brainstorm\n| User phrase | Run immediately |\n|---|---|\n| "retrospective / look back / wrap up" | \`leerness retro\` |\n| "retro for last N days" | \`leerness retro --days N\` |\n| "stats / cumulative metrics / insights" | \`leerness insights\` |\n| "brainstorm about X / materials on X / review before starting X" | \`leerness brainstorm "X"\` |\n\nsession close prints a one-line summary automatically every time and runs a deep retrospective every 5 sessions; call the commands immediately when the user asks explicitly.\n\n## Natural-language standing rules\nWhen the user states a standing rule ("do Y every X"), register it immediately:\n\n| User phrase | Run immediately |\n|---|---|\n| "bump the version every update" | \`leerness rule add "bump version (patch)" --trigger every-update\` |\n| "add patch notes every commit" | \`leerness rule add "add patch notes" --trigger every-commit\` |\n| "deploy at session close" | \`leerness rule add "deploy (release publish)" --trigger session-close\` |\n| "pause/stop rule X" | \`leerness rule pause <ID>\` (find the ID with \`rule list\`) |\n| "remove rule X" | \`leerness rule remove <ID>\` |\n| "stop all rules" | \`leerness rule stop\` |\n| "resume rules" | \`leerness rule resume-all\` or \`leerness rule resume <ID>\` |\n\nAfter registering, report the result (ID + trigger + description) and apply it every session until the user explicitly says stop/remove.\n\n## Automatic rule verification\n- **every-update / version rules**: checks package.json version change.\n- **CHANGELOG / patch-note rules**: checks CHANGELOG.md mtime.\n- **test / verify rules**: checks today's verify traces in review-evidence.md.\n- **deploy / publish / push rules**: not auto-verifiable → guides \`leerness release publish\`.\n\nAutomate verifiable rules with \`leerness release bump\`, \`leerness release note "..."\`, and \`leerness release publish\`.\n`;
669
669
  _files['CLAUDE.md'] = `${MARK}\n# Claude Code Instructions\n\nFollow AGENTS.md. Always run \`leerness handoff .\` at the start and \`leerness session close .\` before ending a session.\n\n**⭐ First action every session**: follow the 6-step workflow in \`.harness/session-workflow.md\` (analyze → plan → distribute → sub-agent → verify → close). On drift critical, recover with \`leerness drift check --auto-fix\`.\n\nProtected files must not be deleted. Read .harness/anti-lazy-work-policy.md before claiming completion.\n\n## Natural-language standing rules\nWhen the user states "do Y every X", immediately run \`leerness rule add "Y" --trigger every-X\`. Registered rules are printed by every \`handoff\` and verified by \`session close\`. Only \`rule pause/remove\` when the user explicitly says stop/remove.\n\nSee the "Natural-language standing rules" table in AGENTS.md for the full mapping.\n`;
670
+ // 1.36.61 (F-05 3회차): .harness 정책·시드 문서군 en 완역 — 지시 5종(1.36.59)에 이어 read-order 가 가리키는 참조층.
671
+ _files['.harness/project-brief.md'] = fm('project-brief', ['confirming project purpose', 'judging new features', 'planning'], ['project purpose changes', 'users/scope change'], `# Project Brief\n\n## Project\n${project}\n\n## Purpose\n- Update this with the real purpose of the project.\n\n## Users\n-\n\n## Success Criteria\n-\n`, 'en');
672
+ _files['.harness/plan.md'] = fm('plan', ['before starting work', 'new request received', 'scope change', 'new project detected'], ['plan add/update/drop', 'milestone changes', 'goal changes'], `# Plan\n\n## Goal\n- Maintain the overall plan around the user's purpose.\n\n## Scope\n- Record what is in scope.\n\n## Out of Scope / Dropped\n| ID | Item | Reason | Date |\n|---|---|---|---|\n\n## Milestones\n\n### M-0001. Organize the project plan\nStatus: planned\nProgress: 0%\n\nTasks:\n- [ ] Fill project-brief.md with the real project purpose\n- [ ] Fill context-map.md with the real file structure\n`, 'en');
673
+ _files['.harness/guideline.md'] = fm('guideline', ['checking quality bar before implementing', 'checking plan-execution criteria'], ['dev standards change', 'verification routine changes'], `# Guideline\n\n## Operating Principle\n- Work against the goal and scope in plan.md.\n- Judge done/not-done by request status in progress-tracker.md.\n- Never record progress percentages here — plan.md/progress-tracker.md are the single source.\n\n## Quality Gate\n- Check the relevant route before changes (\`leerness route <task-type>\`).\n- After changes run \`leerness verify\`, \`leerness audit\`, \`leerness check\`.\n- Before claiming completion run \`leerness lazy detect\`.\n- Close every session with \`leerness session close\`.\n`, 'en');
674
+ _files['.harness/plan-progress-boundary.md'] = fm('plan-progress-boundary', ['when plan and progress overlap', 'work-tracking structure changes'], ['role-separation criteria change'], `# Plan / Progress Boundary\n\n## plan.md\n- Overall goal, milestones, in/out of scope, plan-change history.\n\n## progress-tracker.md\n- Per-request status, evidence, next action.\n- ID rule: T-0001 monotonically increasing; IDs from plan add are unique across plan/progress.\n\n## guideline.md\n- The execution standards to follow while doing plan/progress work.\n`, 'en');
675
+ _files['.harness/current-state.md'] = fm('current-state', ['session start', 'taking over work'], ['current state changes', 'next work changes'], `# Current State\n\nUpdated: ${today()}\n\n## Now\n-\n\n## Next\n-\n\n## Blockers\n-\n`, 'en');
676
+ _files['.harness/writeback-policy.md'] = fm('writeback-policy', ['before finishing work', 'deciding what to update'], ['record targets change'], `# Writeback Policy\n\n- plan.md: user purpose, milestones, scope additions/exclusions\n- progress-tracker.md: per-request status and evidence (updated in place)\n- current-state.md: current state and next work\n- task-log.md: execution history (auto-appended)\n- session-handoff.md: next-session handoff (written by \`session close\`)\n- decisions.md: hard-to-reverse decisions\n- design-system.md: UI/UX/component standards\n- feature-contracts.md: input/output/state/error contracts\n- review-evidence.md: verification results (auto-accumulated)\n`, 'en');
677
+ _files['.harness/task-type-map.md'] = fm('task-type-map', ['classifying user requests'], ['task types added'], `# Task Type Map\n\n| User Request | Task Type | Route |\n|---|---|---|\n| plan this / draft a roadmap | planning | leerness route planning |\n| implement / build a feature | feature | leerness route feature |\n| fix a bug | bugfix | leerness route bugfix |\n| refactor / clean up | refactor | leerness route refactor |\n| research / compare | research | leerness route research |\n| unify design / consistency | consistency | leerness route consistency |\n| deploy / release | release | leerness route release |\n| migration | migration | leerness route migration |\n| session start / resume | session-start | leerness route session-start |\n| session end | session-close | leerness route session-close |\n`, 'en');
678
+ _files['.harness/protected-files.md'] = fm('protected-files', ['before deleting/cleaning/migrating files'], ['protected targets change'], `# Protected Files\n\nAI agents must not delete or reset these files without explicit user approval.\n\n- .harness/\n- .harness/skills/\n- .harness/library/\n- AGENTS.md\n- CLAUDE.md\n- .cursor/rules/leerness.mdc\n- .github/copilot-instructions.md\n- .claude/commands/\n- .claude/skills/\n- README.md Leerness managed section\n\nUse merge, archive, or deprecated markers instead of deletion.\n`, 'en');
679
+ _files['.harness/guardrails.md'] = fm('guardrails', ['before all work', 'before security/permissions/refactoring'], ['prohibition rules change'], `# Guardrails\n\n- Never store tokens/keys/passwords — record only environment-variable names.\n- No unrequested large refactors (user pre-approval when changing 5+ files).\n- Record the impact of API/DB/env-var changes in task-log.\n- Never delete Leerness protected files/managed sections.\n- Keep Korean text as UTF-8 without BOM.\n- Destructive Git operations (\`git reset --hard\`, \`git push --force\`, …) only after explicit user approval.\n`, 'en');
680
+ _files['.harness/consistency-policy.md'] = fm('consistency-policy', ['before duplicating UI/features', 'judging reuse'], ['consistency policy changes'], `# Consistency Policy\n\nBefore building something that does the same job, find and reuse/extend/connect the existing implementation.\n\n## Recursive Reuse Rule\n1. Find existing elements with the same capability.\n2. Check whether self-reference/base rules/recursive flow is needed.\n3. Reuse or extend the existing element.\n4. If you must build new, record why in reuse-map.md.\n\n## Audit Trigger\n\`leerness audit\` checks:\n- duplicate design-guide files\n- undefined design-system.md tokens\n- empty reuse-map.md with 3+ components/utils found\n- plan vs progress alignment\n`, 'en');
681
+ _files['.harness/testing-strategy.md'] = fm('testing-strategy', ['before verification', 'before release'], ['test strategy changes'], `# Testing Strategy\n\n- Typecheck (\`tsc --noEmit\` or equivalent)\n- Lint (\`npm run lint\` etc.)\n- Unit/Integration/E2E\n- Manual smoke test\n- Browser/UI smoke (on frontend changes)\n\n## Evidence Format\nEach completed task must reference an evidence ID stored in .harness/review-evidence.md.\n`, 'en');
682
+ _files['.harness/review-checklist.md'] = fm('review-checklist', ['before PR/review'], ['review criteria change'], `# Review Checklist\n\n- [ ] Aligned with the plan\n- [ ] progress-tracker updated\n- [ ] No protected files deleted\n- [ ] Design/feature reuse checked\n- [ ] No secrets in code (\`leerness scan secrets\`)\n- [ ] Korean encoding OK (\`leerness encoding check\`)\n- [ ] Lazy-work check passed (\`leerness lazy detect\`)\n`, 'en');
683
+ _files['.harness/release-checklist.md'] = fm('release-checklist', ['before deploy'], ['deploy conditions/env vars/rollback change'], `# Release Checklist\n\n- [ ] \`leerness verify .\`\n- [ ] \`leerness audit .\`\n- [ ] \`leerness scan secrets .\`\n- [ ] \`leerness encoding check .\`\n- [ ] project typecheck/lint/test\n- [ ] env vars (.env.example) synced\n- [ ] rollback path confirmed\n- [ ] CHANGELOG updated\n`, 'en');
684
+ _files['.harness/session-close-policy.md'] = fm('session-close-policy', ['before session end'], ['session-close format changes'], `# Session Close Policy\n\nEvery session must list:\n- Completed\n- In progress\n- Incomplete\n- Planned\n- Waiting\n- On hold\n- Blocked\n- Dropped\n- Verification (commands run, results)\n- Recommended next direction\n- Next exact step\n\n\`leerness session close\` extracts the 9 categories automatically and writes the handoff block for the next session into session-handoff.md.\n`, 'en');
685
+ _files['.harness/anti-lazy-work-policy.md'] = fm('anti-lazy-work-policy', ['before claiming completion'], ['lazy-work prevention criteria change'], `# Anti Lazy Work Policy\n\n## Rules\n1. **No completion without evidence**: claiming "done" requires command output/test results/screenshot paths in progress-tracker's evidence column.\n2. **No empty handoff**: if Completed/In Progress/Next Exact Step are all empty at session end, close is marked "insufficient".\n3. **Honest partial implementation**: if not fully implemented, set status \`incomplete\` and write one line in Next Exact Step describing what remains.\n4. **Verification records**: accumulate typecheck/lint/test results in review-evidence.md.\n5. **TODO tracking**: any new \`TODO\`/\`FIXME\`/\`XXX\` in code gets a same-ID row in progress-tracker.\n6. **Automatic false-done detection**: \`leerness lazy detect\` checks done rows without evidence, empty handoffs, untracked new TODOs, and missing test-run traces.\n7. **Quality-lens self-questions**: before claiming done, answer \`leerness lens\` per domain — code: "would a senior developer find this needlessly complex?" / design: "would a senior designer and an ordinary user find it pretty, comfortable, intuitive?". If you cannot answer "yes (pass)", it is not done. When changing one domain, re-check the causally linked domains (↔ in \`lens\` output).\n`, 'en');
686
+ _files['.harness/session-handoff.md'] = fm('session-handoff', ['session start', 'taking over next work'], ['session end'], `# Session Handoff\n\nLast generated: (auto)\n\n## Completed\n-\n\n## In Progress\n-\n\n## Incomplete / Waiting / On Hold / Blocked\n-\n\n## Dropped\n-\n\n## Verification\n-\n\n## Recommended Direction\n-\n\n## Next Exact Step\n-\n`, 'en');
687
+ _files['.harness/leerness-maintenance.md'] = fm('leerness-maintenance', ['work start', 'before migration/release'], ['version policy changes'], `# Leerness Maintenance\n\nAI agents should check:\n\n\`\`\`bash\nleerness --version\nleerness self check .\nleerness update --check # auto-detect with 24h cache\nleerness update --yes # auto-migrate when a new version is found\ncat .harness/HARNESS_VERSION\nnpm view leerness version\n\`\`\`\n`, 'en');
688
+ _files['.harness/language-policy.md'] = fm('language-policy', ['before writing documents'], ['language changes'], `# Language Policy\n\nSelected language: ${lang}\n\nAll Leerness notes, skill notes, session reports, and task lists default to the language above (except when the user explicitly requests another language).\n`, 'en');
689
+ _files['.harness/secret-policy.md'] = fm('secret-policy', ['before skill/deploy/config changes'], ['sensitive-data policy changes'], `# Secret Policy\n\n## Rules\n- Record only environment-variable names; move values to .env.local, CI secrets, or a cloud secret manager.\n- Never leave tokens/passwords/cookies/IDs/card numbers in plaintext in code/docs/logs.\n- Run \`leerness scan secrets .\` before changes.\n\n## Patterns scanned\n- AWS Access Key (\`AKIA[0-9A-Z]{16}\`)\n- GitHub PAT (\`ghp_[A-Za-z0-9]{36}\`)\n- OpenAI key (\`sk-[A-Za-z0-9]{20,}\`)\n- Anthropic key (\`sk-ant-[A-Za-z0-9-]{20,}\`)\n- Google API key, Slack token, generic private key, hardcoded password\n`, 'en');
690
+ _files['.harness/encoding-policy.md'] = fm('encoding-policy', ['before creating files', 'garbled-Korean reports', 'before deploy'], ['encoding policy changes'], `# Encoding Policy\n\n## Rules\n- All text files are **UTF-8 without BOM**.\n- Windows .bat files start with \`chcp 65001 >nul\`.\n- PowerShell .ps1 files start with \`[Console]::OutputEncoding = [System.Text.Encoding]::UTF8\`.\n- Python files may need \`# -*- coding: utf-8 -*-\` (for Python 2 compat).\n- LF line endings recommended (unify via .gitattributes on Windows too).\n\n## Auto check\n\`leerness encoding check\` verifies BOM, NUL, chcp 65001 in .bat, and Korean round-trip.\n`, 'en');
691
+ _files['.harness/architecture.md'] = fm('architecture', ['feature work', 'refactoring', 'migration'], ['structure changes'], `# Architecture\n\n## Overview\n- Record the real structure.\n\n## Data Flow\n-\n\n## External Dependencies\n-\n`, 'en');
692
+ _files['.harness/context-map.md'] = fm('context-map', ['exploring related files', 'before implementing features'], ['file structure changes'], `# Context Map\n\n| Area | Files | Notes |\n|---|---|---|\n| App | src/** | update with real paths |\n| Tests | tests/** | verification paths |\n`, 'en');
693
+ _files['.harness/decisions.md'] = fm('decisions', ['checking design decisions'], ['important decisions made'], `# Decisions\n\n## Template (example — add real decisions below, outside the code block)\n\n\`\`\`md\n### ${today()} — Decision title\n- Decision:\n- Reason:\n- Alternatives:\n- Impact:\n\`\`\`\n`, 'en');
694
+ _files['.harness/task-log.md'] = fm('task-log', ['checking work history'], ['after every meaningful task'], `# Task Log\n\n## ${today()}\n- Leerness v${VERSION} initialized.\n`, 'en');
695
+ _files['.harness/design-system.md'] = fm('design-system', ['UI changes', 'adding components', 'merging design guides'], ['design standards change', 'reusable patterns found'], `# Design System\n\n## Canonical File\nThis file is the canonical design guide (over designguide.md, design-guide.md, etc.).\n\n## Tokens\n| Token | Value | Notes |\n|---|---|---|\n| color.primary | (update with real value) | |\n| color.surface | | |\n| spacing.unit | | |\n| typography.body | | |\n\n## Reusable Patterns\n| Pattern | Where | Reuse Rule |\n|---|---|---|\n`, 'en');
696
+ _files['.harness/reuse-map.md'] = fm('reuse-map', ['before creating new components/APIs/helpers', 'duplicate capability detected'], ['reusable elements added'], `# Reuse Map\n\n| Capability | Existing Element | Reuse Method | Notes |\n|---|---|---|---|\n`, 'en');
697
+ _files['.harness/feature-contracts.md'] = fm('feature-contracts', ['before implementing/changing features'], ['feature IO/state/error changes'], `# Feature Contracts\n\n## Template\n- Feature:\n- Input:\n- Output:\n- States:\n- Errors:\n- Related files:\n- Test evidence ID:\n`, 'en');
670
698
  _files['.cursor/rules/leerness.mdc'] = `${MARK}\n---\nalwaysApply: true\n---\nFollow AGENTS.md and .harness/context-routing.md.\nRun: \`leerness handoff .\` at session start.\nRun: \`leerness session close .\` at session end.\nPreserve Leerness protected files.\n`;
671
699
  _files['.github/copilot-instructions.md'] = `${MARK}\n# Copilot Instructions\n\nUse AGENTS.md and .harness/ as project memory.\nDo not remove protected Leerness files.\nBefore completion, ensure plan.md, progress-tracker.md, current-state.md, session-handoff.md are updated.\n`;
672
700
  _files['.harness/session-workflow.md'] = fm('session-workflow', ['session start', 'new user request arrives', 'before distributing complex work'], ['workflow step changes'], `# Session Workflow — 6 steps of AI harness engineering\n\n> **At the start of every session the main agent reads this document first and follows the 6 steps as written.**\n> Same flow regardless of round length/complexity — that is what prevents drift.\n\n## Step 1. Analyze the request + check the environment\n\`\`\`bash\nleerness handoff . # load context + automatic drift warning\nleerness drift check . # signals + 4-level verdict\n\`\`\`\n- Decompose the request (5W1H). If ambiguous, ask clarifying questions (except autonomous mode).\n- On drift critical, run \`leerness session close .\` or \`drift check --auto-fix\` first.\n\n## Step 2. Plan\n- 3+ steps → use TodoWrite or \`leerness plan add\`.\n- New capability → search existing assets first via \`leerness reuse-map\` / \`reuse find <query>\`.\n- Multiple modules → define an integration spec up front (e.g. TICK_SPEC.md).\n\n## Step 3. Distribute — sub-agent mapping\n\`\`\`bash\nleerness agents list # ready CLIs\nleerness agents quota # limits\nleerness agents dispatch "<task>" --to <id>\n\`\`\`\n- Best sub-agent by task type: text/translation/analysis → claude · deep code reasoning → codex · direct file edits → agy --yolo · security review → \`leerness review --persona security\`.\n- **Conflict-prevention rules (mandatory)**: give each sub-agent *the exact files only it may modify*; require mtime-verification reports (concurrent writes risk last-writer-wins); verify against the spec afterwards with \`leerness contract verify\`.\n\n## Step 4. Sub-agent work + individual self-verification\n- Each sub-agent reports only after passing its own module tests.\n- Report format: line counts, tests N/N PASS, issues found, mtime verification.\n\n## Step 5. Integrated verification\n\`\`\`bash\nleerness contract verify SPEC.md src/<mod>.js\nleerness verify-claim T-XXX --run-tests --strict-claims\nleerness review <file> --persona security,performance,ux\n\`\`\`\n- The main agent writes and runs its own integration scenario (independent verification).\n- Cross-check that sub-agent verification and main verification *agree*.\n\n## Step 6. Close + handoff + next-round suggestion\n\`\`\`bash\nleerness session close . # --suggest on by default\nleerness session close . --no-suggest\n\n# or separately:\nleerness skill suggest .\nleerness drift check .\nleerness audit . --fix\n\`\`\`\n\n## 🧠 Memory CRUD Quick Reference\n\n| Surface | CREATE | READ | DELETE | RESTORE |\n|---|---|---|---|---|\n| **tasks** | task add | task list --json | task drop | task update |\n| **decisions** | decision add | decision list --json | decision drop | memory restore decisions |\n| **lessons** | lesson save | lesson list [--tag] | lesson drop | memory restore lessons |\n| **plan** | plan add | plan list --json | plan remove | memory restore plan |\n| **rules** | rule add | rule list --json | rule remove | (rule pause/resume) |\n\n\`\`\`bash\nleerness memory status [--json]\nleerness memory archive list [--surface s]\nleerness memory restore <surface> <target>\n\`\`\`\n\n**Recovering a wrongly saved item**:\n1. \`memory archive list\` — list restore candidates\n2. \`memory restore decisions "PostgreSQL"\` — archive → active\n3. handoff automatically notes archive activity within 24h every session\n\n## Auto-recovery & security\n- A skipped session close triggers drift critical at the next session start — recover with \`drift check --auto-fix\` (runs session close automatically on critical).\n- handoff auto-recalls past lessons (by current task keywords) and auto-suggests installed skills.\n- handoff prints a 1–2 line security summary (.env ↔ .env.example sync + .gitignore secret gaps); a missing .env in .gitignore is 🚨 CRITICAL — \`LEERNESS_AUTO_SECURITY_FIX=1\` runs \`audit --fix\` automatically.\n- \`leerness health\` gives a one-line combined check (drift + security + skills + usage + tasks).\n\n---\n\n## Quick checklist (before the session ends)\n- [ ] This round's tasks are registered in plan/progress-tracker (or task sync)\n- [ ] Every done item has evidence attached (verify-claim PASS)\n- [ ] contract verify PASS when sub-agents were used\n- [ ] drift score ≤ 30 — \`leerness drift check\`\n- [ ] session close was run\n- [ ] \`leerness health\` overall check\n- [ ] If .env is used: .gitignore secret patterns OK + .env.example synced\n- [ ] On security critical: \`LEERNESS_AUTO_SECURITY_FIX=1\` or \`audit --fix\`\n\n## Anti-patterns (drift signals)\n- ⚠ "work is done, just report and stop" → missed session close → drift critical next session\n- ⚠ "only TodoWrite updated, leerness unused" → \`task sync --from\` or \`task add\` is mandatory\n- ⚠ distributing to sub-agents without explicit file paths → concurrent-write conflicts\n- ⚠ self-reported "tests ran, PASS" only → verify-claim --run-tests not executed\n- ⚠ skipping contract verify → spec-mismatch bugs reach the user\n`, 'en');
@@ -1010,6 +1038,12 @@ async function install(root, opts = {}) {
1010
1038
  const managedOverwrite = new Set([
1011
1039
  'AGENTS.md','CLAUDE.md','.cursor/rules/leerness.mdc','.github/copilot-instructions.md',
1012
1040
  '.harness/session-workflow.md', // 1.36.60 (검수 #1): managed 편입 — 종전엔 재init 시 구 언어/구 버전 그대로 방치
1041
+ // 1.36.61 (검수 High): 순수 정책-문서 전체를 managed 병합 경로에 — 언어 전환 시 구 언어로 방치되던 나머지
1042
+ // (사용자 상태 문서 plan/brief/decisions 등은 제외 — 구조-인지 전략 필요, 데이터라 raw 교체 금지)
1043
+ '.harness/guideline.md','.harness/plan-progress-boundary.md','.harness/guardrails.md',
1044
+ '.harness/consistency-policy.md','.harness/testing-strategy.md','.harness/review-checklist.md',
1045
+ '.harness/release-checklist.md','.harness/session-close-policy.md','.harness/anti-lazy-work-policy.md',
1046
+ '.harness/secret-policy.md','.harness/encoding-policy.md','.harness/language-policy.md',
1013
1047
  '.harness/HARNESS_VERSION','.harness/manifest.json','.harness/LANGUAGE','.harness/skills-lock.json',
1014
1048
  '.harness/context-routing.md','.harness/writeback-policy.md','.harness/task-type-map.md',
1015
1049
  '.harness/leerness-maintenance.md','.harness/protected-files.md','.harness/AX_MIGRATION_GUIDE.md',
@@ -10122,7 +10156,7 @@ function lazyDetect(root, opts = {}) {
10122
10156
  if (rows.length === 0) { issues++; _warn('progress-tracker is empty (no tasks tracked)',
10123
10157
  { kind: 'progress_empty', severity: 'warn' }); }
10124
10158
  const handoff = exists(handoffPath(root)) ? read(handoffPath(root)) : '';
10125
- if (!handoff.includes('Last generated:') || handoff.includes('Last generated: (자동)')) {
10159
+ if (!handoff.includes('Last generated:') || handoff.includes('Last generated: (자동)') || handoff.includes('Last generated: (auto)')) { // 1.36.61 (검수): en 센티널 병기
10126
10160
  issues++; _warn('session-handoff.md never auto-generated',
10127
10161
  { kind: 'handoff_never_generated', severity: 'warn' });
10128
10162
  }
@@ -17251,7 +17285,7 @@ function uiConsistency(root) {
17251
17285
  if (!m) continue;
17252
17286
  const key = m[1].trim();
17253
17287
  const val = m[2].trim();
17254
- if (key === 'Token' || /^-+$/.test(key) || val === 'Value' || /실제 값으로 업데이트/.test(val) || !val) continue;
17288
+ if (key === 'Token' || /^-+$/.test(key) || val === 'Value' || /실제 값으로 업데이트|update with real value/i.test(val) || !val) continue; // 1.36.61: en placeholder 병기
17255
17289
  tokens[key] = val;
17256
17290
  }
17257
17291
  const tokenSet = new Set(Object.values(tokens).map(v => v.toLowerCase()));
package/lib/audit.js CHANGED
@@ -55,7 +55,7 @@ function audit(root, opts = {}, deps = {}) {
55
55
  const naMarker = '<!-- leerness:na';
56
56
  const ds = exists(path.join(root,'.harness/design-system.md')) ? read(path.join(root,'.harness/design-system.md')) : '';
57
57
  if (ds.includes(naMarker)) ok('design-system.md marked NA (skipped)');
58
- else if (!/\| color\.primary \|/.test(ds) || /\(실제 값으로 업데이트\)/.test(ds)) { warnings++; warn('design-system.md tokens not customized'); _finding('design_system_default', 'warn', 'design-system.md tokens not customized'); }
58
+ else if (!/\| color\.primary \|/.test(ds) || /\(실제 값으로 업데이트\)|\(update with real value\)/i.test(ds)) { warnings++; warn('design-system.md tokens not customized'); _finding('design_system_default', 'warn', 'design-system.md tokens not customized'); } // 1.36.61: en placeholder 병기
59
59
  else ok('design-system tokens populated');
60
60
  const reuse = exists(path.join(root,'.harness/reuse-map.md')) ? read(path.join(root,'.harness/reuse-map.md')) : '';
61
61
  const reuseLines = reuse.split('\n').filter(l => l.startsWith('|') && !/Capability|---/.test(l)).length;
@@ -87,12 +87,12 @@ function audit(root, opts = {}, deps = {}) {
87
87
  }
88
88
  else if (milestoneIds.length) ok('all milestones linked in progress-tracker');
89
89
  const handoff = exists(handoffPath(root)) ? read(handoffPath(root)) : '';
90
- if (handoff.includes('Last generated: (자동)')) {
90
+ if (handoff.includes('Last generated: (자동)') || handoff.includes('Last generated: (auto)')) { // 1.36.61: en 센티널 병기
91
91
  warnings++; warn('session-handoff.md never auto-generated (run: leerness session close .)');
92
92
  _finding('handoff_not_generated', 'warn', 'session-handoff.md never auto-generated');
93
93
  // 1.9.35 #5: --fix → session-handoff.md 자동 생성 마커 갱신
94
94
  if (fix) {
95
- const stamped = handoff.replace('Last generated: (자동)', `Last generated: ${today()} (leerness audit --fix)`);
95
+ const stamped = handoff.replace(/Last generated: \((자동|auto)\)/, `Last generated: ${today()} (leerness audit --fix)`); // 1.36.61: 양 언어 --fix
96
96
  writeUtf8(handoffPath(root), stamped);
97
97
  ok(' ↳ fixed: session-handoff.md timestamp 갱신');
98
98
  fixed++;
package/lib/pure-utils.js CHANGED
@@ -352,7 +352,7 @@ function _roadmapParseTokens(text) {
352
352
  const m = line.match(/^\|\s*([\w.\-]+)\s*\|\s*([^|]+?)\s*\|/);
353
353
  if (!m) continue;
354
354
  const key = m[1].trim(), val = m[2].trim();
355
- if (!key || !val || key === 'Token' || /^-+$/.test(key) || val === 'Value' || /\(실제 값으로 업데이트\)/.test(val)) continue;
355
+ if (!key || !val || key === 'Token' || /^-+$/.test(key) || val === 'Value' || /\(실제 값으로 업데이트\)|\(update with real value\)/i.test(val)) continue; // 1.36.61: en placeholder 병기
356
356
  if (val.length > 80) continue;
357
357
  tokens[key] = val;
358
358
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "leerness",
3
- "version": "1.36.60",
3
+ "version": "1.36.61",
4
4
  "description": "The AI-coding operations layer that makes \"done\" require evidence — persistent memory, evidence-gated completion checks, and clean handoffs for any AI agent (Claude Code, Codex, Cursor). State lives as plain files in your repo. CLI + MCP, 0 runtime dependencies.",
5
5
  "keywords": [
6
6
  "leerness",
package/scripts/e2e.js CHANGED
@@ -7083,7 +7083,9 @@ total++;
7083
7083
  const H = /[가-힣]/;
7084
7084
  const de = fs.mkdtempSync(path.join(os.tmpdir(), 'leerness-en5-')); _dirs.push(de);
7085
7085
  const r1 = cp.spawnSync(process.execPath, [CLI, 'init', de, '--yes', '--language', 'en', '--no-env'], { encoding: 'utf8', timeout: 30000 });
7086
- const five = ['AGENTS.md', 'CLAUDE.md', '.harness/session-workflow.md', '.cursor/rules/leerness.mdc', '.github/copilot-instructions.md'];
7086
+ // 1.36.61 (3회차): 정책·시드 문서군까지 확대 대표 10종 무한글
7087
+ const five = ['AGENTS.md', 'CLAUDE.md', '.harness/session-workflow.md', '.cursor/rules/leerness.mdc', '.github/copilot-instructions.md',
7088
+ '.harness/guideline.md', '.harness/guardrails.md', '.harness/anti-lazy-work-policy.md', '.harness/plan.md', '.harness/secret-policy.md'];
7087
7089
  const enOk = r1.status === 0 && five.every(p => { const t = fs.readFileSync(path.join(de, p), 'utf8'); return t.length > 100 && !H.test(t); });
7088
7090
  // en 지시 본문의 핵심 계약 존재(번역이 빈 껍데기가 아님) — 검수 #2 반영: lens 질문/체크리스트/안티패턴/자동화 지시까지
7089
7091
  const ag = fs.readFileSync(path.join(de, 'AGENTS.md'), 'utf8');