Skip to content

Flight recorder 2/5: write-behind capture (events survive process death) #50

Description

@mibrahimdev

Part of the flight-recorder persistence epic — design: docs/superpowers/specs/2026-08-21-flight-recorder-persistence-design.md, discussion #27. Sequenced after #49.

Deliverable

After this slice: events captured during a run are written to disk and survive process death — the core flight-recorder value.

Scope

  • Add an internal var onRecord: ((SharinganEvent) -> Unit)? seam to SharinganStore.record(), invoked after the CAS append (only while recording). Internal → not part of the public API → no noop mirror, parity untouched. The lock-free CAS append is unchanged.
  • PersistenceController: owns a CoroutineScope(SupervisorJob() + Dispatchers.Default), sets onRecord = { channel.trySend(it) } (bounded Channel, non-blocking O(1)).
  • Flusher coroutine drains the channel, batches by size-or-time (~50 events / 250 ms), writes each batch in one SQLDelight transaction {}.
  • Lazy session row created on the first event of the process launch (hands-free, one session per launch).
  • EventDto @Serializable sealed type (Http/Mqtt/Ble) with fromEvent() — encode only is needed this slice; decode lands in slice 3. Public event ABI (Freeze event-type ABI: make HttpEvent/MqttEvent/BleEvent constructors internal #15) untouched — DTO is a separate mirror.

TDD / acceptance

  • RED→GREEN: burst of N events (N > ring capacity 300) all reach the DB — proves no ring-buffer eviction loss.
  • Flusher batches rather than one-write-per-event (assert transaction count).
  • record() hot path unchanged when persistence is off (onRecord == null).
  • Existing in-memory SharinganStoreTest still green; checkApiParity green (no public change).

Activity

  1. 29 remaining items

  2. mibrahimdev commented on Sep 1, 2026

    @mibrahimdev
    OwnerAuthor

    Delivered by #56 (merged 2026-09-01, 31201e3).

    All acceptance criteria are covered by merged tests:

    Criterion Test
    Events beyond ring capacity still reach the DB Given an onRecord seam When the buffer evicts an event Then the evicted event was still forwarded
    Flusher batches rather than one write per event Given many events When flushed Then they are written in batches not one per event
    record() hot path unchanged when persistence is off When persistence is off Then record keeps its behavior and onRecord stays null
    Existing SharinganStoreTest green + checkApiParity green verified on the merged branch

    Shipped beyond the original scope, following the pre-merge review:

    • Bodies are not written to disk — slice 5's default (Flight recorder 5/5: disk security (bodies off by default, clear-on-new-session) #53), pulled forward rather than shipping the opposite default in the interim. Flight recorder 5/5: disk security (bodies off by default, clear-on-new-session) #53 has been rescoped accordingly.
    • Sharingan.clear() now purges disk rows via an onClear seam. The clear travels as a command on the write channel, so a pending batch cannot resurrect cleared events.
    • Persistence.stop() — the seam had no teardown; it now unwires and closes, and the seams are wired before the flusher starts rather than after.
    • :sharingan-db is BCV- and ktlint-guarded. The module was published to Maven Central while excluded from apiValidation, so its ABI shipped unwatched; it was also outside the ktlint gate. Both exemptions are removed. The gate immediately caught the PersistenceController.clear() widening this PR introduced.
    • Docs corrected — nine stale "memory-only / never persisted" claims across README, ARCHITECTURE, CONTEXT, AGENTS and llms.txt; CONTEXT.md gained Flight Recorder / Write-Behind Seam / Run.

    Known gap: Persistence.start/stop have no unit test. start() builds a real driver and DriverFactory.create() on Android needs the ContentProvider-installed Context, which a JVM unit test cannot supply — covering it would need Robolectric or a controller-injection seam. Documented in the type's KDoc.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions