leerness 1.36.302 → 1.36.303

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,11 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.36.303 - 2026-10-15
4
+
5
+ - Fixed (tests): `scripts/ci-shard.js` passed its own `LEERNESS_CI_SHARD_TIMES` to the leaves it runs, so `scripts/ci-shard-probe.js`, which runs the runner itself, overwrote the outer run's times file in the middle of a local full run (found in a full run for this release; the outer runner rewrote the file at its end, so the stored times were right). Leaves no longer see the variable, the way `e2eShard` already hides its own. CI does not set it. A new probe case fails on the 1.36.302 runner (13/14) and passes now (14/14) (T-0364).
6
+ - Not shipped: T-0357, removing the temp folders a test made after it ends with exit code 0, was planned for this release in a simplified form. Its four review rounds found 16 more problems in the exit-time decision and in which folders it records (6, 6, 2 and 2; the first 14 fixed, each with a test that fails on the reviewed code). By the owner's decision before the fourth round, this release ships only the change above, and T-0357 continues separately.
7
+ - Not changed: `contract verify` still counts exports written inside comments and strings. This was investigated and deferred on purpose in 1.36.18 (a comment masker without a parser deleted real code in review, which blocks valid contracts); T-0361 is on hold until a real parser is an option.
8
+
3
9
  ## 1.36.302 - 2026-10-14
4
10
 
5
11
  - Fixed (tests): store-values-probe's two `skill publish` tests failed when a run crossed UTC midnight (T-0358; seen once in a Linux Docker node:20 run during the 1.36.299 release).
package/README.md CHANGED
@@ -195,7 +195,7 @@ MIT
195
195
  <!-- leerness:project-readme:start -->
196
196
  ## Leerness Project Harness
197
197
 
198
- 이 프로젝트는 Leerness v1.36.302 하네스를 사용합니다. AI 에이전트는 작업 전 `leerness handoff`로 컨텍스트를 적재하고, 작업 후 `leerness check`/`leerness audit`/`leerness session close`를 수행해야 합니다.
198
+ 이 프로젝트는 Leerness v1.36.303 하네스를 사용합니다. AI 에이전트는 작업 전 `leerness handoff`로 컨텍스트를 적재하고, 작업 후 `leerness check`/`leerness audit`/`leerness session close`를 수행해야 합니다.
199
199
 
200
200
  ### 정체성 — AI 에이전트 운영 레이어 (UR-0030)
201
201
 
@@ -249,7 +249,7 @@ leerness memory restore decision <date|title>
249
249
 
250
250
  ### MCP server (외부 AI 통합)
251
251
 
252
- Leerness v1.36.302는 stdio JSON-RPC MCP server를 내장합니다 — Claude Code · Cursor · Codex CLI 등 외부 AI에 **102개 도구**를 노출:
252
+ Leerness v1.36.303는 stdio JSON-RPC MCP server를 내장합니다 — Claude Code · Cursor · Codex CLI 등 외부 AI에 **102개 도구**를 노출:
253
253
 
254
254
  ```jsonc
255
255
  // 카테고리별
@@ -270,7 +270,7 @@ Leerness v1.36.302는 stdio JSON-RPC MCP server를 내장합니다 — Claude Co
270
270
  `<<autonomous-loop-dynamic>>` 신호만 보내면 AI가:
271
271
  1) 다음 라운드 후보 선정 → 2) 코드 변경 → 3) 회귀 테스트 갱신 → 4) 전체 e2e 스위트 통과 → 5) npm publish + git tag → 6) main push → 7) session close → 8) 다음 라운드 예약.
272
272
 
273
- 현재 사용 중인 하네스 버전: **1.36.302**. 공개 릴리스 여부는 공개 저장소의 태그와 배포 기록에서 별도로 확인합니다.
273
+ 현재 사용 중인 하네스 버전: **1.36.303**. 공개 릴리스 여부는 공개 저장소의 태그와 배포 기록에서 별도로 확인합니다.
274
274
 
275
275
  ### 성능 가이드
276
276
 
@@ -308,7 +308,7 @@ leerness release pack --close --auto-main-push
308
308
  - `.leerness/session-handoff.md`: 다음 세션 인수인계 (자동 작성)
309
309
  - `.leerness/lessons.md` / `decisions.md` / `rules.md`: 영구 메모리 (5 surface)
310
310
 
311
- Last synced by Leerness v1.36.302: 2026-09-30
311
+ Last synced by Leerness v1.36.303: 2026-09-30
312
312
  <!-- leerness:project-readme:end -->
313
313
  GitHub 로그인 계정 확인용 서버 어댑터: [설정·연결·승인과의 구분](docs/github-login.md). 실제 앱 등록/브라우저 세션 연결과 대상별 승인은 후속입니다.
314
314
 
package/bin/leerness.js CHANGED
@@ -115,7 +115,7 @@ const {
115
115
  migrateLegacyWorkspace,
116
116
  } = require('../lib/workspace-dir');
117
117
 
118
- const VERSION = '1.36.302';
118
+ const VERSION = '1.36.303';
119
119
 
120
120
  // MCP lifecycle 주소 표식은 현재 CLI 호출 한 번에만 유효하다. CLI bootstrap에서 즉시 env에서
121
121
  // 떼어 두어 `--no-record`/hook처럼 presence 기록 함수에 도달하지 않는 경로도 후속 child에 유출하지 않는다.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "leerness",
3
- "version": "1.36.302",
3
+ "version": "1.36.303",
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",
@@ -136,6 +136,21 @@ try {
136
136
  assert.deepStrictEqual(s1.results.map(r => r.key), ['node ./a.js', 'node ./d.js']);
137
137
  });
138
138
 
139
+ check('runNpm keeps LEERNESS_CI_SHARD_TIMES to itself: leaves do not see it, the runner still writes its times', () => {
140
+ // 1.36.303: the full run's times file was overwritten mid-run by this probe's own runNpm, which inherited the
141
+ // variable from the outer runner through the leaf environment.
142
+ const dir = path.join(arena, 'times-env');
143
+ fs.mkdirSync(dir);
144
+ const seen = path.join(dir, 'seen.txt'), times = path.join(dir, 'times.json');
145
+ fs.writeFileSync(path.join(dir, 'e.js'), `require('fs').writeFileSync(${JSON.stringify(seen)}, Object.keys(process.env).filter(k => k.toUpperCase() === 'LEERNESS_CI_SHARD_TIMES').length ? 'set' : 'unset');\n`);
146
+ const env = { ...process.env, GITHUB_ACTIONS: '', LEERNESS_CI_SHARD_TIMES: times };
147
+ const r = cs.runNpm('suite', { index: 1, count: 1 }, { root: dir, scripts: { suite: 'node ./e.js' }, weights: { e2e: {}, npm: {} }, stdio: 'ignore', env, log: () => {} });
148
+ assert.deepStrictEqual(r.failed, []);
149
+ assert.strictEqual(fs.readFileSync(seen, 'utf8'), 'unset', 'a leaf saw the runner\'s times variable');
150
+ assert.deepStrictEqual(Object.keys(JSON.parse(fs.readFileSync(times, 'utf8'))), ['node ./e.js'], 'the runner did not write its own times');
151
+ assert.strictEqual(env.LEERNESS_CI_SHARD_TIMES, times, 'the caller\'s environment object was changed');
152
+ });
153
+
139
154
  const CREATE = names => `const e2eShard = require('./ci-shard').e2eShard(__filename, [${names.map(n => `'${n}'`).join(', ')}]);`;
140
155
  const START = '// e2e-shard: cases start here';
141
156
 
@@ -137,12 +137,15 @@ function runNpm(name, spec, opts = {}) {
137
137
  const mine = leaves.filter(l => l.shard === spec.index);
138
138
  const log = opts.log || (line => process.stdout.write(line + '\n'));
139
139
  const grouped = env.GITHUB_ACTIONS === 'true';
140
+ // Leaves do not see this runner's times file: a leaf that runs runNpm itself (ci-shard-probe.js) would overwrite it.
141
+ const leafEnv = { ...env };
142
+ for (const k of Object.keys(leafEnv)) if (k.toUpperCase() === 'LEERNESS_CI_SHARD_TIMES') delete leafEnv[k];
140
143
  log(`ci-shard: ${name} shard ${spec.index}/${spec.count} runs ${mine.length} of ${leaves.length} leaves`);
141
144
  const results = [];
142
145
  for (const leaf of mine) {
143
146
  if (grouped) log(`::group::${leaf.key}`);
144
147
  const started = Date.now();
145
- const r = cp.spawnSync(process.execPath, [path.resolve(root, leaf.file), ...leaf.args], { cwd: root, stdio: opts.stdio || 'inherit', env });
148
+ const r = cp.spawnSync(process.execPath, [path.resolve(root, leaf.file), ...leaf.args], { cwd: root, stdio: opts.stdio || 'inherit', env: leafEnv });
146
149
  const seconds = (Date.now() - started) / 1000;
147
150
  const ok = r.status === 0 && !r.signal && !r.error;
148
151
  results.push({ key: leaf.key, ok, seconds, status: r.status, signal: r.signal || null, error: r.error ? String(r.error.code || r.error.message) : null });