a digital entity named phi that roams bsky phi.zzstoatzz.io
2
fork

Configure Feed

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

fix reconciliation, activity feed, and connection serialization

- use patch_rows instead of upsert_rows when marking observations superseded (fixes empty vector error)
- show replies in homepage activity feed (posts_and_author_threads)
- remove erroneous .upper() on connectionType (lexicon values are lowercase)
- fix test assertions to match actual record shape

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

zzstoatzz 38b83882 21a0b731

+20 -15
+5 -1
src/bot/main.py
··· 485 485 async with httpx.AsyncClient(timeout=10) as client: 486 486 posts_coro = client.get( 487 487 "https://public.api.bsky.app/xrpc/app.bsky.feed.getAuthorFeed", 488 - params={"actor": PHI_DID, "filter": "posts_no_replies", "limit": 10}, 488 + params={ 489 + "actor": PHI_DID, 490 + "filter": "posts_and_author_threads", 491 + "limit": 10, 492 + }, 489 493 ) 490 494 cards_coro = client.get( 491 495 "https://bsky.social/xrpc/com.atproto.repo.listRecords",
+2 -6
src/bot/memory/namespace_memory.py
··· 252 252 # mark old row superseded, write merged version linking back 253 253 old_id = best_match["id"] 254 254 user_ns.write( 255 - upsert_rows=[{"id": old_id, "status": "superseded"}], 256 - distance_metric="cosine_distance", 257 - schema=USER_NAMESPACE_SCHEMA, 255 + patch_rows=[{"id": old_id, "status": "superseded"}], 258 256 ) 259 257 merged = Observation( 260 258 content=decision.new_content or obs.content, ··· 272 270 # mark old row superseded, write new one linking back 273 271 old_id = best_match["id"] 274 272 user_ns.write( 275 - upsert_rows=[{"id": old_id, "status": "superseded"}], 276 - distance_metric="cosine_distance", 277 - schema=USER_NAMESPACE_SCHEMA, 273 + patch_rows=[{"id": old_id, "status": "superseded"}], 278 274 ) 279 275 await self._write_observation(handle, obs, embedding, supersedes=old_id) 280 276 logger.info(
+1 -1
src/bot/types.py
··· 117 117 "updatedAt": now, 118 118 } 119 119 if self.connection_type: 120 - record["connectionType"] = self.connection_type.upper() 120 + record["connectionType"] = self.connection_type 121 121 if self.note: 122 122 record["note"] = self.note 123 123 return record
+12 -7
tests/test_types.py
··· 36 36 note="because reasons", 37 37 ) 38 38 record = conn.to_record() 39 - assert record == { 40 - "source": "https://a.com", 41 - "target": "https://b.com", 42 - "connectionType": "supports", 43 - "note": "because reasons", 44 - } 39 + assert record["source"] == "https://a.com" 40 + assert record["target"] == "https://b.com" 41 + assert record["connectionType"] == "supports" 42 + assert record["note"] == "because reasons" 43 + assert "createdAt" in record 44 + assert "updatedAt" in record 45 45 46 46 47 47 def test_connection_to_record_minimal(): 48 48 conn = CosmikConnection(source="https://a.com", target="https://b.com") 49 49 record = conn.to_record() 50 - assert record == {"source": "https://a.com", "target": "https://b.com"} 50 + assert record["source"] == "https://a.com" 51 + assert record["target"] == "https://b.com" 52 + assert "connectionType" not in record 53 + assert "note" not in record 54 + assert "createdAt" in record 55 + assert "updatedAt" in record 51 56 52 57 53 58 def test_connection_rejects_bare_string():