From df779bae30ef7a286da4c91754d3622cd4bfd956 Mon Sep 17 00:00:00 2001 From: Mohamed Ibrahim Date: Sun, 14 Jun 2026 15:15:20 +0100 Subject: [PATCH] docs: roadmap entry for persistent per-session log storage (#27) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Records the flight-recorder persistence path discussed 2026-06-14: persist events to a local DB so logs survive crashes, group per session, and let a consumer dump previous sessions. Captures the design constraints (noop parity, SQLDelight-vs-Room, write-behind hot path, schema, retention-as-configure, on-disk security) and defers implementation to a design session (#27) after 1.0. This is also why #18 (in-memory configure(capacity)) was dropped — the capacity knob becomes a retention policy once persistence lands. Co-Authored-By: Claude Opus 4.8 (1M context) --- docs/ROADMAP.md | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md index 273d2bb..8487ba8 100644 --- a/docs/ROADMAP.md +++ b/docs/ROADMAP.md @@ -4,6 +4,46 @@ Future enhancements, recorded but not scheduled. Items here are deliberately out of scope for current work; pick one up when its motivating use case becomes a priority. +## Storage & persistence — "flight recorder" (v2 epic) + +**Status: needs a design session before any code — see [#27](https://github.com/mibrahimdev/Sharingan/issues/27).** + +Today `SharinganStore` is an in-memory ring buffer (capacity 300); logs are lost +on process death. The proposal is to persist captured events to a local on-device +database so logs **survive crashes**, are grouped **per session**, and a consumer +can **dump previous sessions' logs anytime** (flight-recorder model). + +Why it's worth doing: the logs you most want are the ones right before a crash — +exactly what an in-memory buffer loses. Per-session history also enables a "send +me the logs from your last run" QA workflow. + +Design constraints to settle in the session (full list in #27): + +- **Noop parity is sacred.** Persistence must live *entirely behind* the existing + `SharinganStore` surface (`record()` / `events: StateFlow` / `clear()`). + `:sharingan-noop` stays empty/in-memory with a byte-identical public API and + **zero DB dependency** — it ships in release builds. No DB type may leak into + the public API. +- **DB engine — decide:** SQLDelight (KMP-first, lean, mature on Native — current + lean) vs Room KMP (2.7+, Android-familiar, heavier on iOS). +- **Protect the hot path.** `record()` is a lock-free CAS on an in-memory list; + don't write to disk per event. Use a **write-behind buffer** — the in-memory + `StateFlow` stays the live UI window, batches flush to the DB on a background + dispatcher. The DB augments the ring buffer; it doesn't replace it. +- **Schema:** session table (id, started-at, app/build/device meta) + events table + (FK session, timestamp, type, indexed cols + `kotlinx.serialization` JSON blob). + Composes with the event ABI frozen in #15. +- **Retention policy** (max sessions / age / rows-per-session) is what + `configure(capacity)` (closed #18) becomes — added additively once persistence + exists, which is why the simple in-memory capacity knob was dropped. +- **Security must be designed in, not bolted on.** A SQLite file is extractable; + persisting request/response bodies can write tokens/PII to disk. Need + bodies-off-by-default for persistence, redaction, retention/auto-purge, + clear-on-new-session. Debug-only mitigates but isn't sufficient alone. + +Sequencing: ship 1.0 on the in-memory architecture first (close the parity check +#12), then take persistence on as a deliberate v2 epic. + ## iOS / Swift ergonomics - **iOS-friendly Swift `log()` overload.** The pure-Swift capture path