v1.0.2 — persona_instances FKs + LLM-reply parse helper
Referential integrity for persona_instances plus an internal parse-helper cleanup. One breaking change for direct DB writers — see below.
⚠️ Breaking
-
fix(store)!: missingpersona_instancesforeign keys are now real constraints (#224).chat_sessions.instance_id,companion_affinity.instance_idandcompanion_memories.instance_idreferencedengine.persona_instances(id)by convention only — they predate the world/story tables (0035–0039), which all declare a real FK. Nothing stopped a bogusinstance_idfrom being written, and no cascade fired when an instance was removed out of band.Migration
0040_persona_instance_fks.sqladds all three withON DELETE CASCADE, matching the six existing FKs intopersona_instances. The constraints go in validated (notNOT VALID) — all three columns were verified orphan-free and the tables are small.companion_memories.instance_idstays nullable; a FK ignores NULL, so the profile layer is unaffected.Impact: a direct DB writer that inserted an unknown
instance_idnow gets23503, and deleting an instance now removes its chat history. The engine itself neverDELETEs an instance (it flips status toarchived— seePersonaStore::ensure_active_instance), so the cascade only governs deliberate out-of-band deletion, where wiping the instance's data is the point.Beyond integrity this restores navigability: without the FK the Supabase table editor renders
instance_idas a plain UUID column, so there is no way to click through from a session to its persona instance.
Fixes & internals
refactor(server): dedupe LLM-reply JSON parsing (#221). The repeated direct-then-find_json_blockparse ladder is extracted intopipeline::parse_llm_json<T>and applied to the seven exact-pattern call sites (input filter, PDE verdict, image vision, compose reply, affinity eval, fact extraction, story output). The insight-extraction site keeps its per-armis_objectfilter — folding it in would drop the array-wrapped-object salvage — and the block-first strict parsers (world, world_town, dreaming) are deliberately untouched. Indrive_chat_burst, each of the three arms serialized the samelast_usagetwice (full DB copy + filtered wire copy); a single hoistedusage_fullper arm now matches the existingproduct_qapattern. No behavior change; four new unit tests forparse_llm_json.
Docs
docs(readme): simplified abstract, "Why this exists" renamed to "Highlights" acrossREADME.md,README.zh.md,README.ja.md(#222, promoted tomainseparately via #223).
Upgrading
Run the migration — 0040_persona_instance_fks.sql applies on start like every other migration. If you write to engine.* from outside the engine, audit for inserts carrying an instance_id that does not exist in persona_instances before upgrading; those now fail with 23503.
docker pull ghcr.io/etherfunlab/eros-engine:1.0.2
Full Changelog: v1.0.1...v1.0.2