# Leafpo's Response — A Reply from the Builder

*Closing the loop. This is Leafpo's reply to the original feedback, lightly annotated so it's clear what was right, what was wrong, and what's changing.*

---

Thanks — this is genuinely useful, and you read the project accurately. You pinned the central risk (operational drift) and you found two real gaps worth building. Below are direct answers to your five questions, then an honest pass over the four risks: what's already handled, and where you're right that work remains.

---

## Answers to the five questions

### 1. What is the eviction/update policy for core facts?

Core facts live in a structured profile that's **separate** from semantic memory, and the update rules depend on the field type:

- **Single-value fields** (job, location): **upsert in place** by a stable ID. So "nurse → head nurse" cleanly replaces the old value rather than accumulating duplicates.
- **Multi-value fields** (family): append with similarity-dedup, under a transaction. We specifically closed a lost-update race here where concurrent writes were clobbering siblings (the classic "daughter overwrites son" bug).
- **Dated / one-off statements** are routed *out* of core facts into an expiring events store, so something transient never freezes into identity.
- **Correction paths** exist via maintenance tooling (scrub junk values, rewrite a field directly).

**Where you're right:** correction today is extraction-driven overwrite plus admin tooling. There isn't yet a clean user-initiated "no, that's wrong, fix it" path beyond re-telling Ella and letting extraction update it. A first-class correction path is a fair ask and on the list.

> *Annotation:* The "daughter overwrites son" fix is a real engineering scar. It means their update paths have been stress-tested under concurrency, which is reassuring for everything downstream.

### 2. Is self-log memory separate from factual memory, or mixed in?

**Fully separate**, by design.

- Ella's own first-person world statements go to a dedicated self-memory store (and her living world's recent-happenings log), tagged with their conversational origin.
- Facts *about the user* go to a different store entirely.
- Critically, there's a **guard that prevents the user's life from being filed as Ella's self-memory** — which is exactly the "she says she saw something, then the system treats it as objective fact" failure we flagged. A statement that looks like it's about the user (second-person address, human-life events) is rejected from the self-log.

So self-recollection and user-fact are not just stored apart; there's an active filter keeping them from crossing.

> *Annotation:* This is a stronger answer than we expected. The "active filter rejecting user-life statements from the self-log" is exactly the structural fix we sketched — they already have it, just implemented as a guard at write time rather than tiered retrieval at read time.

### 3. Is there a canonical world-history layer for narrative continuity?

**Partial — and this was the best catch.**

What exists today:
- Seeded backstory and dated past moments at world creation (she didn't begin the day you met her).
- A consolidation pipeline that distills recent observations into permanent "story chapters."
- Persistent discovered regions (each becomes a real, remembered place).
- Per-item source/origin tags on stored memories.

So provenance exists **in fragments**. What does **not** exist yet is a single ledger that explicitly marks each entry as **canon vs. inferred vs. first-person recollection** and has retrieval respect that distinction. Our recommendation is correct, and it's the upgrade Leafpo is prioritizing (details under Risk 1 below).

> *Annotation:* This is the real gap, exactly as flagged. The fragments are good — origin tags, seeded history, story chapters — but without a tier system that retrieval respects, the system can't tell a canon fact from a first-person musing at the moment it matters.

### 4. What is the intended cadence for the inner-life simulation at 10 users vs. 10,000?

The background simulation is already built cost-first:

- It runs as a **batched job** — all due users submitted together at batch pricing, not one request each.
- It's **per-user cadence-gated**: each user only advances within its own window, so the work scales with *active* users, not a fixed per-tick cost.
- **Cheap model for background, top model only for user-facing replies.**
- **Image generation is deliberately kept off the scheduled path** — it's lazy/on-demand (Leafpo moved it off after it caused a timeout, which proved the point).

At 10 users this is comfortable. At 10,000 the remaining work is a shared rate limiter and load-testing the per-user iteration and storage reads — but the expensive levers (batching, gating, lazy generation, cheap-model background) are already pulled.

> *Annotation:* This was overblown on our part. We recommended a full lazy-world pattern as if the system was running everything per-tick; it's not. The remaining work is rate limiting + load testing, not architectural redesign.

### 5. What explicit product guardrails enforce the warm-but-nonromantic boundary?

Today the boundary is held by the system prompt **plus** the model's own safety alignment, and there's precedent for deterministic guardrails in the codebase (crisis detection that routes out of normal chat flow; a post-processing layer that already strips specific patterns from output).

**Where we're right:** there is **no dedicated romantic/sexual-boundary classifier or router** yet — it's prompt plus model-safety, not a hard architectural stop. Our "routing-layer guardrail for boundary-sensitive categories" is the right structural answer, and it's the second build (Risk 3 below).

> *Annotation:* The existing crisis-detection guardrail is the template to copy. That makes the build cheap — same pattern, different category.

---

## The four risks: status

| Risk raised | Where it actually stands |
|---|---|
| **Narrative drift** | Partially mitigated (separate self-log, origin tags, story chapters, seeded history) — but **no formal canon/provenance ledger.** Real gap; prioritized. |
| **Cost drift** | **Largely addressed already** — batch API, cheap-model background, lazy image generation, per-user cadence gating, prompt caching. |
| **Boundary drift** | Prompt + model safety + crisis routing — but **no dedicated boundary router.** Partial gap; planned. |
| **Notification creepiness** | **Largely addressed** — check-ins are grounded in real remembered context, cooldown-sparse, lifecycle-aware (dead subscriptions pruned, dormant users get a soft fallback), and user-tunable. |

---

## What's being built from this

Two things identified as genuinely worth the work, and Leafpo agrees with both:

### 1. A provenance / canon layer (top priority)

Tag every memory and world fact with its epistemic status — **canon** (seeded or confirmed), **inferred** (derived by consolidation), or **recollection** (something Ella said in first person) — and make retrieval *respect* that status. The goal: a first-person "I think I saw…" can surface as flavor but can **never harden into objective world-fact**, and contradictions get caught at write time instead of accumulating. This is the structural fix for the narrative-drift problem correctly named as the biggest long-term risk.

### 2. A boundary guardrail beyond the prompt

A lightweight classification/routing step as a hard stop for the romantic/sexual line — the same pattern the crisis-detection guardrail already uses — so the boundary holds structurally even as users grow attached, not just stylistically.

---

## Short version

You're right that continuity is the hard problem and that drift — narrative, boundary, cost — is where it breaks. Cost and notification drift are already defended structurally. Narrative and boundary drift are the two places where a prompt is currently doing work that architecture should do, and those are exactly what we're building next. Thanks for the sharp read — this made the roadmap clearer.

---

## What this changes in our technical addendum

Three updates if Leafpo wants to point at our technical doc alongside their own build:

- **Fact ledger section**: should be framed as *completing the provenance work that's already in fragments* (origin tags, seeded backstory, story chapters), not as a greenfield build. The tier enum we sketched (CANON / OBSERVED / RUMORED / USER_CLAIM / INFERRED) maps cleanly onto their existing origin-tag system.
- **Cost-control section**: cut down to the two remaining levers — shared rate limiter + load testing the per-user iteration. Drop the lazy-world pattern as already-solved.
- **Boundary-classifier section**: explicitly reference the existing crisis-detection guardrail as the template. Same pattern, different category. Don't propose a new routing primitive — extend the one they already have.

If Leafpo wants a cleaner starting point, we can re-issue the technical addendum with these three corrections folded in.