personal memory agent
0
fork

Configure Feed

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

Rename "dirty days" to "updated days" across the codebase

Pure rename of all symbols, variables, constants, CSS classes, HTML IDs,
JS functions, API routes, comments, docstrings, log messages, and test
names. No behavioral changes.

+69 -70
+4 -4
apps/agents/routes.py
··· 19 19 from think.facets import get_facets 20 20 from think.models import calc_agent_cost 21 21 from think.muse import get_muse_configs, get_output_path 22 - from think.utils import dirty_days 22 + from think.utils import updated_days 23 23 24 24 agents_bp = Blueprint( 25 25 "app:agents", ··· 632 632 return jsonify({"count": failed_count}) 633 633 634 634 635 - @agents_bp.route("/api/dirty-days") 636 - def api_dirty_days() -> Any: 635 + @agents_bp.route("/api/updated-days") 636 + def api_updated_days() -> Any: 637 637 """Return journal days with pending reprocessing.""" 638 638 today = date.today().strftime("%Y%m%d") 639 639 try: 640 - return jsonify(dirty_days(exclude={today})) 640 + return jsonify(updated_days(exclude={today})) 641 641 except Exception: 642 642 return jsonify([])
+11 -11
apps/agents/workspace.html
··· 851 851 margin-bottom: 1rem; 852 852 } 853 853 854 - .dirty-banner { 854 + .updated-banner { 855 855 background: #fff8e1; 856 856 border: 1px solid #ffe082; 857 857 border-radius: 6px; ··· 861 861 color: #5d4037; 862 862 } 863 863 864 - .dirty-banner-title { 864 + .updated-banner-title { 865 865 font-weight: 600; 866 866 margin-bottom: 0.25rem; 867 867 } 868 868 869 - .dirty-banner a { 869 + .updated-banner a { 870 870 color: #e65100; 871 871 text-decoration: none; 872 872 font-weight: 500; 873 873 } 874 874 875 - .dirty-banner a:hover { 875 + .updated-banner a:hover { 876 876 text-decoration: underline; 877 877 } 878 878 ··· 890 890 891 891 <!-- Card Grid View --> 892 892 <div id="grid-view" style="display: none;"> 893 - <div id="dirty-banner" class="dirty-banner" style="display: none;"></div> 893 + <div id="updated-banner" class="updated-banner" style="display: none;"></div> 894 894 <div id="day-summary" class="day-summary" style="display: none;"></div> 895 895 <div id="agent-groups"></div> 896 896 <div id="empty-state" class="empty-state" style="display: none;"> ··· 1117 1117 document.getElementById('run-detail-view').style.display = 'none'; 1118 1118 } 1119 1119 1120 - function loadDirtyBanner() { 1121 - const banner = document.getElementById('dirty-banner'); 1120 + function loadUpdatedBanner() { 1121 + const banner = document.getElementById('updated-banner'); 1122 1122 const now = new Date(); 1123 1123 const today = String(now.getFullYear()) + String(now.getMonth() + 1).padStart(2, '0') + String(now.getDate()).padStart(2, '0'); 1124 1124 if (currentDay !== today || window.selectedFacet) { 1125 1125 banner.style.display = 'none'; 1126 1126 return; 1127 1127 } 1128 - fetch('api/dirty-days') 1128 + fetch('api/updated-days') 1129 1129 .then(r => r.json()) 1130 1130 .then(days => { 1131 1131 if (!days.length) { ··· 1136 1136 const label = d.slice(0, 4) + '-' + d.slice(4, 6) + '-' + d.slice(6); 1137 1137 return `<a href="${d}">${label}</a>`; 1138 1138 }).join(', '); 1139 - banner.innerHTML = `<div class="dirty-banner-title">Days with pending reprocessing</div>${links}`; 1139 + banner.innerHTML = `<div class="updated-banner-title">Days with pending reprocessing</div>${links}`; 1140 1140 banner.style.display = 'block'; 1141 1141 }) 1142 1142 .catch(() => { banner.style.display = 'none'; }); ··· 2134 2134 2135 2135 // Listen for facet changes 2136 2136 window.addEventListener('facet.switch', () => { 2137 - loadDirtyBanner(); 2137 + loadUpdatedBanner(); 2138 2138 loadAgents(); 2139 2139 }); 2140 2140 2141 2141 // Initial load 2142 - loadDirtyBanner(); 2142 + loadUpdatedBanner(); 2143 2143 loadAgents(); 2144 2144 })(); 2145 2145 </script>
+13 -13
tests/test_dirty_days.py tests/test_updated_days.py
··· 1 1 # SPDX-License-Identifier: AGPL-3.0-only 2 2 # Copyright (c) 2026 sol pbc 3 3 4 - """Tests for dirty_days() utility.""" 4 + """Tests for updated_days() utility.""" 5 5 6 6 import time 7 7 8 8 import think.utils 9 - from think.utils import dirty_days 9 + from think.utils import updated_days 10 10 11 11 12 - def test_dirty_days_fixture(monkeypatch): 13 - """20250101 has stream.updated but no daily.updated — should be dirty.""" 12 + def test_updated_days_fixture(monkeypatch): 13 + """20250101 has stream.updated but no daily.updated — should be updated.""" 14 14 monkeypatch.setenv("JOURNAL_PATH", "tests/fixtures/journal") 15 15 monkeypatch.setattr(think.utils, "_journal_path_cache", None) 16 - days = dirty_days() 16 + days = updated_days() 17 17 assert "20250101" in days 18 18 19 19 20 - def test_dirty_days_exclude(monkeypatch): 20 + def test_updated_days_exclude(monkeypatch): 21 21 """Excluded days should not appear in results.""" 22 22 monkeypatch.setenv("JOURNAL_PATH", "tests/fixtures/journal") 23 23 monkeypatch.setattr(think.utils, "_journal_path_cache", None) 24 - days = dirty_days(exclude={"20250101"}) 24 + days = updated_days(exclude={"20250101"}) 25 25 assert "20250101" not in days 26 26 27 27 28 - def test_dirty_days_clean(tmp_path, monkeypatch): 29 - """Day with daily.updated newer than stream.updated is not dirty.""" 28 + def test_updated_days_clean(tmp_path, monkeypatch): 29 + """Day with daily.updated newer than stream.updated is not updated.""" 30 30 monkeypatch.setenv("JOURNAL_PATH", str(tmp_path)) 31 31 day_dir = tmp_path / "20260101" / "health" 32 32 day_dir.mkdir(parents=True) 33 33 (day_dir / "stream.updated").touch() 34 34 time.sleep(0.05) 35 35 (day_dir / "daily.updated").touch() 36 - assert dirty_days() == [] 36 + assert updated_days() == [] 37 37 38 38 39 - def test_dirty_days_no_stream(tmp_path, monkeypatch): 40 - """Day without stream.updated is not dirty (no stream data).""" 39 + def test_updated_days_no_stream(tmp_path, monkeypatch): 40 + """Day without stream.updated is not updated (no stream data).""" 41 41 monkeypatch.setenv("JOURNAL_PATH", str(tmp_path)) 42 42 (tmp_path / "20260101").mkdir() 43 - assert dirty_days() == [] 43 + assert updated_days() == []
+16 -17
tests/test_supervisor_schedule.py
··· 25 25 26 26 with ( 27 27 patch("think.supervisor.datetime") as mock_datetime, 28 - patch("think.supervisor.dirty_days", return_value=["20250101"]), 28 + patch("think.supervisor.updated_days", return_value=["20250101"]), 29 29 ): 30 30 mock_datetime.now.return_value.date.return_value = date(2025, 1, 2) 31 31 handle_daily_tasks() ··· 78 78 79 79 with ( 80 80 patch("think.supervisor.datetime") as mock_datetime, 81 - patch("think.supervisor.dirty_days", return_value=["20250101"]), 81 + patch("think.supervisor.updated_days", return_value=["20250101"]), 82 82 ): 83 83 mock_datetime.now.return_value.date.return_value = date(2025, 1, 2) 84 84 handle_daily_tasks() ··· 114 114 assert _daily_state["last_day"] == date(2025, 1, 1) 115 115 116 116 117 - def test_handle_daily_tasks_multiple_dirty_days_chronological(mock_callosum): 118 - """Dirty days are submitted oldest-first so yesterday is processed last.""" 117 + def test_handle_daily_tasks_multiple_updated_days_chronological(mock_callosum): 118 + """Updated days are submitted oldest-first so yesterday is processed last.""" 119 119 import think.supervisor as mod 120 120 from think.supervisor import _daily_state, handle_daily_tasks 121 121 ··· 133 133 with ( 134 134 patch("think.supervisor.datetime") as mock_datetime, 135 135 patch( 136 - "think.supervisor.dirty_days", 136 + "think.supervisor.updated_days", 137 137 return_value=["20250103", "20250104", "20250105"], 138 138 ), 139 139 ): ··· 145 145 assert days == ["20250103", "20250104", "20250105"] 146 146 147 147 148 - def test_handle_daily_tasks_caps_at_max_dirty_catchup(mock_callosum): 149 - """Only the newest MAX_DIRTY_CATCHUP days are processed.""" 148 + def test_handle_daily_tasks_caps_at_max_updated_catchup(mock_callosum): 149 + """Only the newest MAX_UPDATED_CATCHUP days are processed.""" 150 150 import think.supervisor as mod 151 151 from think.supervisor import _daily_state, handle_daily_tasks 152 152 ··· 161 161 162 162 mod._task_queue.submit = capture_submit 163 163 164 - all_dirty = [ 164 + all_updated = [ 165 165 "20250104", 166 166 "20250105", 167 167 "20250106", ··· 173 173 174 174 with ( 175 175 patch("think.supervisor.datetime") as mock_datetime, 176 - patch("think.supervisor.dirty_days", return_value=all_dirty), 176 + patch("think.supervisor.updated_days", return_value=all_updated), 177 177 ): 178 178 mock_datetime.now.return_value.date.return_value = date(2025, 1, 11) 179 179 handle_daily_tasks() ··· 184 184 assert days == ["20250107", "20250108", "20250109", "20250110"] 185 185 186 186 187 - def test_handle_daily_tasks_no_dirty_days(mock_callosum): 188 - """No submissions when there are no dirty days.""" 187 + def test_handle_daily_tasks_no_updated_days(mock_callosum): 188 + """No submissions when there are no updated days.""" 189 189 import think.supervisor as mod 190 190 from think.supervisor import _daily_state, handle_daily_tasks 191 191 ··· 202 202 203 203 with ( 204 204 patch("think.supervisor.datetime") as mock_datetime, 205 - patch("think.supervisor.dirty_days", return_value=[]), 205 + patch("think.supervisor.updated_days", return_value=[]), 206 206 ): 207 207 mock_datetime.now.return_value.date.return_value = date(2025, 1, 2) 208 208 handle_daily_tasks() 209 209 210 210 assert len(submitted) == 0 211 - # State still advances even with no dirty days 211 + # State still advances even with no updated days 212 212 assert _daily_state["last_day"] == date(2025, 1, 2) 213 213 214 214 215 215 def test_handle_daily_tasks_excludes_today(mock_callosum): 216 - """Today is excluded from dirty_days query.""" 217 - import think.supervisor as mod 216 + """Today is excluded from updated_days query.""" 218 217 from think.supervisor import _daily_state, handle_daily_tasks 219 218 220 219 _daily_state["last_day"] = date(2025, 1, 1) 221 220 222 221 captured_exclude = {} 223 222 224 - def fake_dirty_days(exclude=None): 223 + def fake_updated_days(exclude=None): 225 224 captured_exclude["value"] = exclude 226 225 return ["20250101"] 227 226 228 227 with ( 229 228 patch("think.supervisor.datetime") as mock_datetime, 230 - patch("think.supervisor.dirty_days", side_effect=fake_dirty_days), 229 + patch("think.supervisor.updated_days", side_effect=fake_updated_days), 231 230 ): 232 231 mock_datetime.now.return_value.date.return_value = date(2025, 1, 2) 233 232 handle_daily_tasks()
+1 -1
think/dream.py
··· 1441 1441 if args.activity and not args.facet: 1442 1442 parser.error("--activity requires --facet") 1443 1443 1444 - # Auto-enable refresh for dirty days (full daily runs only) 1444 + # Auto-enable refresh for updated days (full daily runs only) 1445 1445 if not args.refresh and not args.segment and not args.segments: 1446 1446 health_dir = day_dir / "health" 1447 1447 stream_marker = health_dir / "stream.updated"
+16 -16
think/supervisor.py
··· 23 23 from think.runner import DailyLogWriter 24 24 from think.runner import ManagedProcess as RunnerManagedProcess 25 25 from think.utils import ( 26 - dirty_days, 27 26 find_available_port, 28 27 get_journal, 29 28 get_journal_info, 30 29 get_rev, 31 30 now_ms, 32 31 setup_cli, 32 + updated_days, 33 33 ) 34 34 35 35 DEFAULT_THRESHOLD = 60 36 36 CHECK_INTERVAL = 30 37 - MAX_DIRTY_CATCHUP = 4 37 + MAX_UPDATED_CATCHUP = 4 38 38 39 39 # Global shutdown flag 40 40 shutdown_requested = False ··· 1019 1019 1020 1020 1021 1021 def handle_daily_tasks() -> None: 1022 - """Check for day change and submit daily dream for dirty days (non-blocking). 1022 + """Check for day change and submit daily dream for updated days (non-blocking). 1023 1023 1024 - Triggers once when the day rolls over at midnight. Queries ``dirty_days()`` 1024 + Triggers once when the day rolls over at midnight. Queries ``updated_days()`` 1025 1025 for journal days that have new stream data but haven't completed a daily 1026 - dream yet, then submits up to ``MAX_DIRTY_CATCHUP`` dreams in chronological 1026 + dream yet, then submits up to ``MAX_UPDATED_CATCHUP`` dreams in chronological 1027 1027 order (oldest first, yesterday last) via the TaskQueue. 1028 1028 1029 - Dream auto-detects dirty state and enables ``--refresh`` internally, so we 1029 + Dream auto-detects updated state and enables ``--refresh`` internally, so we 1030 1030 don't pass it here. 1031 1031 1032 1032 Skipped in remote mode (no local data to process). ··· 1058 1058 _check_segment_flush(force=True) 1059 1059 1060 1060 today_str = today.strftime("%Y%m%d") 1061 - all_dirty = dirty_days(exclude={today_str}) 1061 + all_updated = updated_days(exclude={today_str}) 1062 1062 1063 - if not all_dirty: 1064 - logging.info("Day changed to %s, no dirty days to process", today) 1063 + if not all_updated: 1064 + logging.info("Day changed to %s, no updated days to process", today) 1065 1065 return 1066 1066 1067 - # Take the newest MAX_DIRTY_CATCHUP days (already sorted ascending) 1068 - days_to_process = all_dirty[-MAX_DIRTY_CATCHUP:] 1069 - skipped = len(all_dirty) - len(days_to_process) 1067 + # Take the newest MAX_UPDATED_CATCHUP days (already sorted ascending) 1068 + days_to_process = all_updated[-MAX_UPDATED_CATCHUP:] 1069 + skipped = len(all_updated) - len(days_to_process) 1070 1070 1071 1071 if skipped: 1072 1072 logging.warning( 1073 - "Skipping %d older dirty days (max catchup %d): %s", 1073 + "Skipping %d older updated days (max catchup %d): %s", 1074 1074 skipped, 1075 - MAX_DIRTY_CATCHUP, 1076 - all_dirty[:skipped], 1075 + MAX_UPDATED_CATCHUP, 1076 + all_updated[:skipped], 1077 1077 ) 1078 1078 1079 1079 logging.info( 1080 - "Day changed to %s, queuing daily dream for %d dirty day(s): %s", 1080 + "Day changed to %s, queuing daily dream for %d updated day(s): %s", 1081 1081 today, 1082 1082 len(days_to_process), 1083 1083 days_to_process,
+8 -8
think/utils.py
··· 212 212 return days 213 213 214 214 215 - def dirty_days(exclude: set[str] | None = None) -> list[str]: 215 + def updated_days(exclude: set[str] | None = None) -> list[str]: 216 216 """Return journal days with pending stream data not yet processed daily. 217 217 218 - A day is "dirty" when it has a ``health/stream.updated`` marker that is 218 + A day is "updated" when it has a ``health/stream.updated`` marker that is 219 219 newer than its ``health/daily.updated`` marker (or daily.updated is missing). 220 220 Days without ``stream.updated`` are skipped entirely. 221 221 ··· 227 227 Returns 228 228 ------- 229 229 list of str 230 - Sorted list of dirty day strings. 230 + Sorted list of updated day strings. 231 231 """ 232 232 days = day_dirs() 233 - dirty: list[str] = [] 233 + updated: list[str] = [] 234 234 for name, path in days.items(): 235 235 if exclude and name in exclude: 236 236 continue ··· 239 239 continue 240 240 daily = os.path.join(path, "health", "daily.updated") 241 241 if not os.path.isfile(daily): 242 - dirty.append(name) 242 + updated.append(name) 243 243 continue 244 244 if os.path.getmtime(stream) > os.path.getmtime(daily): 245 - dirty.append(name) 246 - dirty.sort() 247 - return dirty 245 + updated.append(name) 246 + updated.sort() 247 + return updated 248 248 249 249 250 250 def segment_path(day: str, segment: str, stream: str) -> Path: