decision
ADR-0019: Session continuity via structured wrap-up logs
ADR-0019 (Proposed, 2026-05-17): Session continuity via structured wrap-up logs.
▶ Watch the 1:22 summary — ADR-0019 — Session continuity via structured wrap-up logs, explained
Status: Proposed
Date: 2026-05-17
Decider: Seth Shoultes (with Blair Williams approval per decision-rights matrix; counsel reviews privacy posture)
Author: Seth Shoultes
Context
Wrap-ups are an additional context layer per the framing note in ADR 0015 — not a fifth “document.” Lifecycle: write-once at session-end, then always-injected by recency (last N) on every subsequent turn. Differs from MEMORY (vector-retrieved by topic, opportunistically written) and BIBLE (always-injected, LLM-edited rolling).
ADR 0015 established the four-document customer brain (SOUL, BIBLE, HEARTBEAT, MEMORY). ADR 0016 gave the LLM tool-call authority to write to SOUL, BIBLE, and MEMORY during a conversation. ADR 0018 bounded MEMORY with per-tier limits and sanitization. Together these define how durable per-user state is acquired and maintained.
What none of these ADRs define is how a session ends. Today the LLM writes MEMORY entries opportunistically — only when it decides mid-conversation that something is worth remembering, and only if it remembers to call the tool. There is no deterministic, every-session capture of what the conversation was about, what was decided, what was left open, or what should prime the next session. The next session begins with the brain’s always-on context (SOUL + BIBLE + HEARTBEAT) plus whatever MEMORY entries vector-retrieval surfaces — which may or may not include anything from the immediately prior conversation.
This produces a specific failure mode. A customer ends a substantive advisory conversation (“here’s my plan to fix churn”) and returns three days later. The next session has no awareness that the plan was made unless the LLM happened to write a MEMORY entry, and even then the entry is only surfaced if the new conversation semantically matches it. The customer gets a generic re-introduction instead of “how did the discount campaign go?” This is the failure mode that most distinguishes a memory-equipped advisor from a stateless chatbot, and it materially harms the differentiation-from-generic-AI-tools risk called out in the Phase 1–2 friction-points one-pager.
The “self-maintaining agent” pattern in the broader industry addresses this with a structured wrap-up capture at session end — a write-once artifact summarizing decisions, open items, and a handoff note for the next session. The question for V1 is whether MemberIntel adopts it, what form it takes, and where it lives relative to the existing brain.
Naming note: external sources sometimes pair this concept with a “heartbeat” — a scheduled background process that syncs external data. That term is already claimed in our codebase for the auto-generated per-site metrics narrative (ADR 0015). The scheduled-sync half of the external pattern is already substantially covered by our MP/Stripe sync pipeline. This ADR adopts only the wrap-up half, and does not introduce any new use of “heartbeat.”
Decision
MemberIntel V1 adds structured session wrap-up logs as a new artifact stored in a new session_logs table, separate from the four brain documents. A wrap-up is:
- Deterministic — produced at the end of every chat session that contains at least one substantive user turn (defined: ≥1 user message with ≥20 tokens). Trivial sessions skip the wrap-up step.
- Structured — five fields:
summary(2–3 sentences),decisions(list),open_items(list),new_context(facts/preferences learned),next_session_note(one sentence priming the next session). - LLM-generated — a server-side wrap-up call against the session transcript via the model provider abstraction (ADR 0009), defaulting to the cheap-tier model. Wrap-up is summarization, not advisory work.
- Capped — output bounded to ~400 words; regenerated with a tighter prompt if the model exceeds the cap.
- Tenant-scoped —
tenant_id UUID NOT NULLper ADR 0003. Wrap-ups participate fully in RLS.
System-prompt assembly (extends ADR 0015’s order): Base prompt → SOUL → BIBLE → HEARTBEAT → last N session wrap-ups (default N=3, by recency) → MEMORY search results → Global brain search results.
Wrap-up triggering: primary signal is clean SSE stream close + substantive-turn threshold met. Fallback is a daily background job that sweeps for sessions that closed without a wrap-up (network drops, server crashes) and generates one from persisted transcripts.
Wrap-ups are user-visible in the brain-management UI (Pro tier, per the ADR 0018 pattern), editable and deletable by the user. The LLM cannot edit a past wrap-up — wrap-ups are write-once at generation. The existing MEMORY artifact is retained unchanged; MEMORY remains the opportunistic mid-conversation durable-insight mechanism, and wrap-ups are the deterministic session-end artifact. They serve different functions and the system holds both.
Alternatives considered
Alternative 1: Status quo — incremental MEMORY writes only
Continue to rely on the LLM’s mid-conversation update_customer_brain(target=memory) calls as the sole mechanism for session persistence.
Strongest argument: it’s already shipping, the cheapest option, and avoids adding LLM cost at session end. MEMORY entries are vector-retrievable, which captures the “surface relevant past conversations” use case when the new question semantically matches.
Rejected because MEMORY’s coverage is non-deterministic. An LLM that doesn’t happen to call the tool during a 30-minute strategic conversation produces zero artifacts; the next session starts cold. The exact failure mode is the one customers will notice — “you don’t remember what we just decided” — and is the most concrete differentiator we have over generic chat tools.
Alternative 2: Persist full session transcripts; retrieve via vector search
Save complete conversation transcripts to a new table, embed and index them, and retrieve by vector search at next-session start, the same as the global brain.
Strongest argument: zero LLM cost at session end (no summarization). Maximum fidelity — nothing is lost in compression.
Rejected on three grounds. First, cost: injecting raw transcript chunks into the next session burns far more input tokens than injecting a structured 200-word wrap-up. Second, signal-to-noise: an LLM reasoning over a 5,000-word transcript chunk does worse than the same LLM reading a 200-word structured summary — consistent with what we already learned in ADR 0015 (“HEARTBEAT replaces build_site_context()” because narrative outperforms data dump). Third, privacy: full transcripts preserve every off-topic remark, draft, or correction; structured wrap-ups give us a natural redaction surface and a tighter retention boundary counsel will prefer.
Alternative 3: Extend MEMORY semantics — wrap-up as a special MEMORY record
Add a kind column to MEMORY entries with values episodic (current) and wrap_up. Wrap-ups live in brain_entries alongside MEMORY.
Strongest argument: no new table, reuses existing retrieval pipeline, minimal schema change.
Rejected because the two artifacts have meaningfully different lifecycle properties: wrap-ups are write-once at session end, structured, always injected by recency (not vector-retrieved), and per-session. MEMORY entries are write-anytime, unstructured, vector-retrieved on relevance, and not session-bound. Conflating them forces every query to filter by kind and makes ADR 0018’s per-tier MEMORY limit ambiguous — do wrap-ups count against the 15-entry Pro cap? Either answer creates a worse mental model than a separate table. A separate session_logs table costs one Alembic migration and produces a cleaner boundary.
Alternative 4: Wrap-up as a fifth always-on brain document
A single rolling “WRAP-UP” document, similar to BIBLE, that the LLM rewrites at each session end via the read-modify-write pattern in ADR 0016.
Strongest argument: keeps the brain symmetric — one document per user, always current, no per-session record-keeping.
Rejected because a single rolling document loses the temporal structure that makes wrap-ups useful. The user and the LLM need “what did we discuss in the last three sessions” not “what’s the current summary of everything ever.” The per-session boundary is the unit of value. A rolling doc also makes the privacy story harder — there’s no clean way to expire a single session’s content without a careful in-place edit.
Consequences
What gets easier:
- A returning customer gets a session that opens with awareness of the prior conversation. The “you don’t remember me” failure mode is closed for any session that produced a wrap-up.
- The longitudinal-memory differentiator vs. generic AI tools becomes concrete and demonstrable — the next-session note is observable evidence the system has memory.
- Eval coverage is straightforward: a wrap-up of a canonical conversation has expected structure and content; the eval suite can assert that injection produces an observable continuity behavior in the next session.
- Privacy retention has a clean surface: “delete wrap-ups older than N” is a table-scoped operation; per-user deletion participates in the GDPR pathway via the same RLS-scoped pattern as the rest of tenant data per ADR 0003.
What gets harder or constrained:
- Every substantive session incurs an LLM call at session end. The entitlement layer must budget this. Default: cheap-tier model, ~500 output tokens. For free-tier users the wrap-up step is the first thing to cap when entitlement is exhausted — the conversation completes, just without a wrap-up.
- Detecting session end reliably is non-trivial. SSE stream close is the primary signal but unreliable across network drops. The daily backfill job is the fallback but introduces a generation lag (acceptable for V1).
- Wrap-ups contain customer PII (member counts, revenue figures, business decisions). They are subject to the same retention, deletion, and access-audit posture as other brain content. Privacy counsel must explicitly review the wrap-up schema, retention period, and export pathway before launch — adds an item to the counsel review agenda.
- The cross-pollination boundary needs a wrap-up policy. Default proposal: the
decisionsandopen_itemsfields may feed the cross-tenant k-anonymity layer in fully-redacted form (no member names, no revenue numbers); rawsummary,new_context, andnext_session_notenever do. The binding policy lands alongside ADR 0011 after counsel review. - The brain-management UI gains a fifth surface (session log list, view, edit, delete). Adds scope to Pro-tier brain features.
Downstream commitments this creates:
- New
session_logstable withtenant_id,session_id,created_at, and the five structured fields. RLS per ADR 0003. - Wrap-up generation step in the chat pipeline triggered on stream close + threshold met.
- Daily background job for fallback wrap-up generation, co-located with the sync pipeline runner.
- Brain-management UI routes: list/view/edit/delete session logs.
- New entitlement charge type:
wrap_up_generation, with per-tier budget allocations. - New eval: “session continuity” — canonical session followed by a follow-up that should reference the prior wrap-up. Asserts the injection pathway works end-to-end. Becomes a release gate per the eval suite policy.
- New counsel review item: wrap-up retention, redaction, deletion, and cross-pollination eligibility.
Deferred deliberately:
- Wrap-up vector retrieval. V1 injects the last N by recency. If wrap-up volume per user grows beyond ~20–30, recency stops capturing the right ones and we add vector retrieval. Tracked under the revisit triggers below.
- Binding wrap-up cross-pollination policy. Default position above is the proposal; the policy lands in a separate ADR with the broader k-anonymity work, after counsel review.
Conditions for revisiting
-
Wrap-up generation cost exceeds 10% of total per-tenant LLM spend. Triggers re-evaluation of the substantive-session threshold or a move to selective wrap-up (advisory sessions only). Detected via monthly entitlement reports.
-
The “you don’t remember me” failure mode persists in customer feedback after wrap-ups are live. Indicates the injection pathway is failing silently or recency-only retrieval is missing the right wrap-up. Triggers an ADR revisit and likely the move to vector retrieval.
-
Wrap-up content quality is poor in the eval suite. Wrap-ups that miss decisions or fabricate open items break the chain. Triggers prompt iteration first, then a move to a stronger model if needed. Threshold: eval pass rate below 85% for two consecutive releases.
-
Privacy counsel raises a retention or export concern the schema can’t accommodate. Triggers schema revision — most likely redaction-at-rest for specific fields or a separate retention period for
decisions/open_itemsvs. free-text fields. -
Wrap-up volume per Pro user exceeds 30/month sustained. At that volume, recency-N=3 injection misses too many relevant logs. Triggers the move to vector retrieval.
-
An enterprise customer requires wrap-up content excluded from cross-pollination entirely. Triggers tightening of the cross-pollination policy, possibly with per-tenant opt-out.
Related
- SPEC-v2 §6 (Cross-pollination)
- SPEC-v2 §10 (Compliance & Privacy)
- ADR-0003 (Per-tenant isolation: shared-schema with RLS)
- ADR-0005 (Anthropic SDK direct, mitigation seam at
llm.call) — wrap-up generation routes through this mitigation seam; specifically to Vertex AI Gemini 2.5 Flash per ADR-0020 - ADR-0011 (Cross-pollination security boundary: three-roles model) — the binding wrap-up cross-pollination policy will be co-located here when finalized
- ADR-0020 (Multi-provider model routing — Vertex AI Gemini as second provider) — defines the routing of wrap-up generation to Vertex AI Gemini Flash
- ADR-0015 (Customer brain: four-document architecture) — this ADR adds a separate artifact alongside the brain, not a fifth brain document
- ADR-0016 (Brain mutation via Anthropic tool calls) — wrap-up generation is a separate server-side code path; it does not go through
update_customer_brain - ADR-0018 (Brain memory limits and content sanitization) — the sanitization policy applies to wrap-up content; wrap-ups are not subject to the MEMORY per-tier limit
- Counsel review agenda — wrap-up retention, redaction, deletion pathway added before the May 31 engagement
- PR #__ —
session_logstable migration (added when implementation lands) - PR #__ — wrap-up generation in chat pipeline (added when implementation lands)
- PR #__ — daily backfill job (added when implementation lands)
- PR #__ — brain-management UI session log surface (added when implementation lands)