diff --git a/scripts/lib/llm-summary.js b/scripts/lib/llm-summary.js index fb9394173..2473b3797 100644 --- a/scripts/lib/llm-summary.js +++ b/scripts/lib/llm-summary.js @@ -112,7 +112,10 @@ function getContextRemainingPct(transcriptPath) { * Returns the summary string, or null on failure or when recursion guard is active. */ function generateSessionSummary(transcriptPath, { onSkip = () => {} } = {}) { - if (process.env.ECC_SKIP_LLM_SUMMARY) return null; + if (process.env.ECC_SKIP_LLM_SUMMARY) { + onSkip('ECC_SKIP_LLM_SUMMARY'); + return null; + } const conversation = extractConversationText(transcriptPath); if (!conversation) return null; diff --git a/tests/hooks/session-end.test.js b/tests/hooks/session-end.test.js index f6010f97e..5b745705c 100644 --- a/tests/hooks/session-end.test.js +++ b/tests/hooks/session-end.test.js @@ -266,6 +266,27 @@ function runTests() { } }) ? passed++ : failed++); + (test('logs an explicit LLM disable as skipped and persists mechanical resume state', () => { + const home = fs.mkdtempSync(path.join(os.tmpdir(), 'ecc-session-skip-')); + try { + const uuid = '12345678-1234-4234-8234-123456789abc'; + const transcript = path.join(home, `${uuid}.jsonl`); + const bin = path.join(home, 'empty-bin'); + fs.mkdirSync(bin); + fs.writeFileSync(transcript, JSON.stringify({ type: 'user', content: 'Save context with LLM disabled' }) + '\n'); + const res = runHook(home, transcript, { + ECC_LLM_SUMMARY_INTERVAL: '1', ECC_SKIP_LLM_SUMMARY: '1', + ECC_LLM_SUMMARY_SUBPROCESS: '', PATH: bin + }); + assert.strictEqual(res.status, 0, res.stderr); + assert.match(res.stderr, /LLM summary skipped.*ECC_SKIP_LLM_SUMMARY/); + assert.doesNotMatch(res.stderr, /LLM summary failed/); + assert.match(fs.readFileSync(sessionFileFor(home, uuid), 'utf8'), /Save context with LLM disabled/); + } finally { + fs.rmSync(home, { recursive: true, force: true }); + } + }) ? passed++ : failed++); + for (const inherited of ['', String(Date.now() + 300000), '1']) { (test(`direct legacy runner bounds the deadline ${inherited || '(unset)'}`, () => { const home = fs.mkdtempSync(path.join(os.tmpdir(), 'ecc-runner-budget-')); diff --git a/tests/lib/llm-summary.test.js b/tests/lib/llm-summary.test.js index db1b8f65a..f836d20c4 100644 --- a/tests/lib/llm-summary.test.js +++ b/tests/lib/llm-summary.test.js @@ -185,6 +185,21 @@ test('returns null when ECC_SKIP_LLM_SUMMARY is set', () => { else delete process.env.ECC_SKIP_LLM_SUMMARY; }); +test('reports the explicit recursion guard as a deliberate skip', () => { + const orig = process.env.ECC_SKIP_LLM_SUMMARY; + process.env.ECC_SKIP_LLM_SUMMARY = '1'; + try { + const skipped = []; + assert.strictEqual(generateSessionSummary('/nonexistent.jsonl', { + onSkip: reason => skipped.push(reason) + }), null); + assert.deepStrictEqual(skipped, ['ECC_SKIP_LLM_SUMMARY']); + } finally { + if (orig !== undefined) process.env.ECC_SKIP_LLM_SUMMARY = orig; + else delete process.env.ECC_SKIP_LLM_SUMMARY; + } +}); + test('returns null for missing transcript (no conversation to summarize)', () => { const orig = process.env.ECC_SKIP_LLM_SUMMARY; delete process.env.ECC_SKIP_LLM_SUMMARY;