Skip to content

fix(analysis): negative-cache failed generations so they stop minting sessions - #14

Merged
michaeloboyle merged 1 commit into
mainfrom
feature/analysis-failure-negative-cache
Jun 7, 2026
Merged

fix(analysis): negative-cache failed generations so they stop minting sessions#14
michaeloboyle merged 1 commit into
mainfrom
feature/analysis-failure-negative-cache

Conversation

@michaeloboyle

Copy link
Copy Markdown
Owner

Problem

Tribbles' daily/weekly analysis generator spawns a headless claude --print session per period to write analyses/{key}.json (rendered by the visualizer). Each such run mints a permanent Claude Code session transcript under ~/.claude/projects/.

The success path was already gated: trigger_analysis_generation() skips any key whose analyses/{key}.json exists. But _run_analysis only wrote that cache file on a clean returncode==0 + parseable JSON. A day whose generation failed (non-zero exit, unparseable output, timeout) left no trace, so it re-spawned a fresh session on every dashboard load — unbounded session minting.

Fix

Negative-cache failures with a {key}.failed marker:

  • _analysis_blocked(key) — skip generation if a cached analysis exists or a failure marker is still within ANALYSIS_FAIL_COOLDOWN (24h).
  • _run_analysis records a failure on every error path and clears the marker on success → self-healing: at most one retry per cooldown instead of one per page load.
  • Both gate points in trigger_analysis_generation now use _analysis_blocked.
  • Markers use a .failed suffix, so the /api/analyses *.json glob never serves them as analyses.

Behavior change

  • Before: failing day → new session every dashboard load, forever.
  • After: failing day → at most one session per 24h; succeeds once → cached forever (unchanged).
  • Successful-cache and cold-start behavior are unchanged.

Tests

tests/test_analysis_cache.py — 6 stdlib unittest cases (no subprocess, no server boot): cold cache allows, success blocks, failure negative-cached within cooldown, marker expires after cooldown (one retry), success clears marker, markers not served as *.json.

Ran 6 tests in 0.003s — OK
python3 -m py_compile serve.py — OK

🤖 Generated with Claude Code

… sessions

The daily/weekly analysis generator already gated on success
(analyses/{key}.json exists -> skip). But _run_analysis only wrote the
cache on a clean returncode + parseable JSON. A day whose generation
failed (non-zero exit, unparseable output, timeout) left no trace, so
trigger_analysis_generation re-spawned a fresh headless 'claude --print'
session for it on EVERY dashboard load -- unbounded session minting.

Add a {key}.failed negative-cache marker:
  - _analysis_blocked(key): skip if a cached analysis exists OR a failure
    marker is still within ANALYSIS_FAIL_COOLDOWN (24h)
  - _run_analysis records a failure on every error path, and clears the
    marker on success (self-healing: one retry allowed per cooldown)
  - gate points in trigger_analysis_generation now use _analysis_blocked

Markers use a .failed suffix, so the /api/analyses *.json glob never
serves them. Adds tests/test_analysis_cache.py (6 cases, stdlib unittest,
no subprocess/server boot).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings June 7, 2026 14:43
@michaeloboyle
michaeloboyle merged commit 396d30d into main Jun 7, 2026
2 checks passed
@michaeloboyle
michaeloboyle deleted the feature/analysis-failure-negative-cache branch June 7, 2026 14:43

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a negative-cache for failed analysis generations so the dashboard doesn’t continuously spawn new headless Claude sessions for periods that repeatedly fail to generate.

Changes:

  • Introduces {key}.failed marker files with a 24h cooldown gate to skip re-generation after failures.
  • Records failure markers on all _run_analysis error paths and clears them on success.
  • Adds focused unittest coverage for the gating/marker behavior.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
serve.py Adds failure-marker helpers and uses _analysis_blocked to gate generation; records/clears markers in _run_analysis.
tests/test_analysis_cache.py Adds unit tests covering success caching, failure cooldown behavior, marker expiry, and API glob safety.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread serve.py
Comment on lines +608 to +611
try:
last = float(marker.read_text().strip() or 0)
except (ValueError, OSError):
last = 0.0
Comment thread serve.py
Comment on lines 686 to +690
if not _analysis_semaphore.acquire(timeout=60):
return
try:
out_path = ANALYSES_DIR / f"{key}.json"
if out_path.exists():
if _analysis_blocked(key):
Comment on lines +24 to +31
def setUp(self):
self._tmp = tempfile.TemporaryDirectory()
self.dir = Path(self._tmp.name)
# Redirect all analysis I/O at the temp dir for the duration of the test.
serve.ANALYSES_DIR = self.dir

def tearDown(self):
self._tmp.cleanup()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants