personal memory agent
0
fork

Configure Feed

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

retention: flip default to always-retain for new installs

new journals now default to mode=keep, days=null. existing
journals with on-disk retention config are unchanged.

+33 -20
+6 -7
convey/root.py
··· 257 257 if gemini_key: 258 258 config.setdefault("env", {})["GOOGLE_API_KEY"] = gemini_key 259 259 config.setdefault("setup", {})["completed_at"] = now_ms() 260 - retention_mode = data.get("retention_mode", "days") 261 - retention_days = data.get("retention_days", 7) 262 - if isinstance(retention_days, str): 263 - try: 264 - retention_days = int(retention_days) 265 - except (ValueError, TypeError): 266 - retention_days = 7 260 + retention_mode = data.get("retention_mode", "keep") 261 + retention_days = data.get("retention_days") 262 + if retention_mode == "days" and ( 263 + not isinstance(retention_days, int) or retention_days < 1 264 + ): 265 + return jsonify({"error": "retention_days must be a positive integer"}), 400 267 266 config.setdefault("retention", {}).update( 268 267 { 269 268 "raw_media": retention_mode,
+3 -3
tests/test_init.py
··· 367 367 assert config["retention"]["raw_media_days"] is None 368 368 369 369 def test_finalize_default_retention(self, fresh_client, journal_copy): 370 - """Finalize without retention fields writes default (days/7).""" 370 + """Finalize without retention fields writes default (keep/null).""" 371 371 resp = fresh_client.post( 372 372 "/init/finalize", 373 373 json={"password": "securepass123"}, ··· 375 375 ) 376 376 assert resp.status_code == 200 377 377 config = _read_config(journal_copy) 378 - assert config["retention"]["raw_media"] == "days" 379 - assert config["retention"]["raw_media_days"] == 7 378 + assert config["retention"]["raw_media"] == "keep" 379 + assert config["retention"]["raw_media_days"] is None 380 380 381 381 382 382 class TestRemovedEndpoints:
+18 -4
tests/test_retention.py
··· 223 223 class TestRetentionConfig: 224 224 def test_default_policy(self): 225 225 cfg = RetentionConfig() 226 - assert cfg.policy_for_stream("default").mode == "days" 227 - assert cfg.policy_for_stream("default").days == 7 226 + assert cfg.policy_for_stream("default").mode == "keep" 227 + assert cfg.policy_for_stream("default").days is None 228 228 229 229 def test_per_stream_override(self): 230 230 cfg = RetentionConfig( ··· 247 247 def test_default_config(self, monkeypatch): 248 248 monkeypatch.setattr("think.utils.get_config", lambda: {}) 249 249 cfg = load_retention_config() 250 - assert cfg.default.mode == "days" 251 - assert cfg.default.days == 7 250 + assert cfg.default.mode == "keep" 251 + assert cfg.default.days is None 252 252 assert cfg.per_stream == {} 253 253 254 254 def test_custom_config(self, monkeypatch): ··· 268 268 assert cfg.default.mode == "days" 269 269 assert cfg.default.days == 30 270 270 assert cfg.per_stream["default"].mode == "processed" 271 + 272 + def test_existing_journal_days_config_unchanged(self, monkeypatch): 273 + monkeypatch.setattr( 274 + "think.utils.get_config", 275 + lambda: { 276 + "retention": { 277 + "raw_media": "days", 278 + "raw_media_days": 7, 279 + } 280 + }, 281 + ) 282 + cfg = load_retention_config() 283 + assert cfg.default.mode == "days" 284 + assert cfg.default.days == 7 271 285 272 286 273 287 # ---------------------------------------------------------------------------
+2 -2
think/journal_default.json
··· 53 53 "token_ttl_seconds": 600 54 54 }, 55 55 "retention": { 56 - "raw_media": "days", 57 - "raw_media_days": 7, 56 + "raw_media": "keep", 57 + "raw_media_days": null, 58 58 "per_stream": {}, 59 59 "storage_warning_disk_percent": 80, 60 60 "storage_warning_raw_media_gb": null
+4 -4
think/retention.py
··· 147 147 class RetentionPolicy: 148 148 """Retention policy for a single scope (global or per-stream).""" 149 149 150 - mode: str = "days" # "keep", "days", or "processed" 151 - days: int | None = 7 150 + mode: str = "keep" # "keep", "days", or "processed" 151 + days: int | None = None 152 152 153 153 def is_eligible(self, segment_age_days: int) -> bool: 154 154 """Check if a segment's raw media should be purged under this policy.""" ··· 180 180 config = get_config() 181 181 retention = config.get("retention", {}) 182 182 183 - mode = retention.get("raw_media", "days") 184 - days = retention.get("raw_media_days", 7) 183 + mode = retention.get("raw_media", "keep") 184 + days = retention.get("raw_media_days", None) 185 185 default = RetentionPolicy(mode=mode, days=days) 186 186 187 187 per_stream: dict[str, RetentionPolicy] = {}