personal memory agent
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

sol: surface updated-days server failures

Return 500 with an error envelope from api_updated_days instead of a
silent 200 [], and migrate loadUpdatedBanner to apiJson with logError.
On refresh failure while the banner is visible, append a staleness row
and keep the pending-days links; on first-paint failure render an
unknown-status indicator. Never hide the banner on a failed health
check.

+63 -5
+2 -1
apps/sol/routes.py
··· 641 641 try: 642 642 return jsonify(updated_days(exclude={today})) 643 643 except Exception: 644 - return jsonify([]) 644 + logging.exception("api_updated_days failed") 645 + return jsonify({"error": "Unable to load updated days"}), 500 645 646 646 647 647 648 @sol_bp.route("/api/identity")
+45 -4
apps/sol/workspace.html
··· 928 928 color: #5d4037; 929 929 } 930 930 931 + .updated-banner-stale { 932 + margin-top: 8px; 933 + padding-top: 8px; 934 + border-top: 1px solid #ffe082; 935 + font-size: 0.9em; 936 + color: #5d4037; 937 + } 938 + 939 + .updated-banner-unknown { 940 + color: #5d4037; 941 + } 942 + 931 943 .updated-banner-title { 932 944 font-weight: 600; 933 945 margin-bottom: 0.25rem; ··· 1362 1374 1363 1375 function loadUpdatedBanner() { 1364 1376 const banner = document.getElementById('updated-banner'); 1377 + if (!banner) return; 1378 + 1379 + const clearIndicators = () => { 1380 + banner.querySelectorAll('.updated-banner-stale, .updated-banner-unknown').forEach(el => el.remove()); 1381 + }; 1382 + const hasPendingContent = () => banner.style.display !== 'none' && !!banner.querySelector('.updated-banner-title'); 1383 + 1384 + clearIndicators(); 1385 + 1365 1386 const now = new Date(); 1366 1387 const today = String(now.getFullYear()) + String(now.getMonth() + 1).padStart(2, '0') + String(now.getDate()).padStart(2, '0'); 1367 1388 if (currentDay !== today || window.selectedFacet) { 1368 1389 banner.style.display = 'none'; 1369 1390 return; 1370 1391 } 1371 - fetch('api/updated-days') 1372 - .then(r => r.json()) 1392 + window.apiJson('/app/sol/api/updated-days') 1373 1393 .then(days => { 1374 - if (!days.length) { 1394 + clearIndicators(); 1395 + if (!Array.isArray(days) || !days.length) { 1396 + banner.innerHTML = ''; 1375 1397 banner.style.display = 'none'; 1376 1398 return; 1377 1399 } ··· 1382 1404 banner.innerHTML = `<div class="updated-banner-title">Days with pending reprocessing</div>${links}`; 1383 1405 banner.style.display = 'block'; 1384 1406 }) 1385 - .catch(() => { banner.style.display = 'none'; }); 1407 + .catch(err => { 1408 + window.logError(err, { context: 'sol-updated-days' }); 1409 + if (hasPendingContent()) { 1410 + if (!banner.querySelector('.updated-banner-stale')) { 1411 + const stale = document.createElement('div'); 1412 + stale.className = 'updated-banner-stale'; 1413 + stale.textContent = 'Status check failed — reload to refresh.'; 1414 + banner.appendChild(stale); 1415 + } 1416 + return; 1417 + } 1418 + 1419 + clearIndicators(); 1420 + banner.innerHTML = ''; 1421 + const unknown = document.createElement('div'); 1422 + unknown.className = 'updated-banner-unknown'; 1423 + unknown.textContent = 'Status check failed; unknown if pending.'; 1424 + banner.appendChild(unknown); 1425 + banner.style.display = 'block'; 1426 + }); 1386 1427 } 1387 1428 1388 1429 async function loadTalents() {
+16
tests/test_app_sol.py
··· 322 322 """Non-existent file returns 404.""" 323 323 resp = agents_client.get("/app/sol/api/output/20260214/talents/nonexistent.md") 324 324 assert resp.status_code == 404 325 + 326 + 327 + class TestApiUpdatedDays: 328 + """Tests for api_updated_days endpoint.""" 329 + 330 + def test_logs_and_returns_500_on_failure(self, agents_client, monkeypatch): 331 + """updated_days failures return a detectable error envelope.""" 332 + 333 + def boom(**_kwargs): 334 + raise RuntimeError("simulated") 335 + 336 + monkeypatch.setattr("apps.sol.routes.updated_days", boom) 337 + resp = agents_client.get("/app/sol/api/updated-days") 338 + assert resp.status_code == 500 339 + payload = resp.get_json() 340 + assert "error" in payload