diff --git a/docs/kaizen/real-repo-sync.md b/docs/kaizen/real-repo-sync.md index 64b64ec..4c8b4ed 100644 --- a/docs/kaizen/real-repo-sync.md +++ b/docs/kaizen/real-repo-sync.md @@ -324,22 +324,29 @@ three runs earlier), mmap live 1868 KB, odb cache 70 KB. ~2.8 s commit on a microcontroller, four theories refuted on the way) stands on its own. -**Next steps** +**Next steps** (each now owned by a version doc or done — this list is the +historical record, the owner is authoritative) - Close the gap to the ≤ ~10 s target: publish is 19.8 s; the splice's 5.0 s and the ~7 s of repo-open/negotiation overhead are the next curves. + → [v0.7](../v0.7-search-and-git.md). - The keep-alive race is **avoided, not fixed** (3.5 s ≪ ~30 s) — a future multi-pack or cold-cache state could still lose it. Durable fix: reconnect-on-stale-connection in the http/stream layer. -- Internal RAM min-ever hit **2099 bytes** during the TLS send (the diagnostic - heartbeat's 8 KB stack is part of it) — shrink or retire the heartbeat now - that it has served its purpose. -- Fold `git repack -ad` into the `_load-repo` recipe so single-pack card prep - is enforced, not remembered. + → [v0.9](../v0.9-robustness.md). +- ~~Internal RAM min-ever hit **2099 bytes** during the TLS send (the + diagnostic heartbeat's 8 KB stack is part of it) — shrink or retire the + heartbeat now that it has served its purpose.~~ **Done 2026-07-13** — + heartbeat removed; the time-gated `pack_progress` + transfer callbacks stay. +- ~~Fold `git repack -ad` into the `_load-repo` recipe so single-pack card + prep is enforced, not remembered.~~ **Done 2026-07-13** — `_load-repo` + repacks the source clone (best-effort, like the pull) whenever it has more + than one pack or a multi-pack-index. - File the libgit2 upstream bug report (tlsf double-free in the mbedTLS - stream error path). + stream error path). *(Unscheduled chore — not version-scoped.)* - Instrument the residual ~360 ms/loose-write (suspect: FAT directory-op cost in the freshen/refresh path) — one `sd_bench` + `p_mmap`-miss logging pass. + → [v0.7](../v0.7-search-and-git.md). - The images-off-card lever ([`../notes/git-sync-images-and-repo-size.md`](../notes/git-sync-images-and-repo-size.md)) - composes with the splice. + composes with the splice. → [v0.7](../v0.7-search-and-git.md). diff --git a/docs/postmortems/2026-07-05-spike3-sd-cmd59.md b/docs/postmortems/2026-07-05-spike3-sd-cmd59.md index 6891b53..e224a0e 100644 --- a/docs/postmortems/2026-07-05-spike3-sd-cmd59.md +++ b/docs/postmortems/2026-07-05-spike3-sd-cmd59.md @@ -202,7 +202,8 @@ it is explicitly **not recommended** and not applied. (ADR-012, 2026-07-11); spike rewired to SPI3 (SCK 14 / MOSI 15) and **re-verified on hardware 2026-07-11** — same mount + round-trip result. - [ ] **Still open:** implement the FatFS atomic-save (unlink-then-rename + - `*.tmp` boot-recovery) in the real `persistence` module. + `*.tmp` boot-recovery) in the real `persistence` module — → tracked as + the crash-safe-writes item in [v0.9 robustness](../v0.9-robustness.md). ## Artifacts (this session) diff --git a/docs/postmortems/2026-07-11-editor-freeze-spi-dma-oom-during-sync.md b/docs/postmortems/2026-07-11-editor-freeze-spi-dma-oom-during-sync.md index 978c0d4..7ada9b0 100644 --- a/docs/postmortems/2026-07-11-editor-freeze-spi-dma-oom-during-sync.md +++ b/docs/postmortems/2026-07-11-editor-freeze-spi-dma-oom-during-sync.md @@ -1,11 +1,16 @@ # Editor freeze — SPI-DMA out-of-memory during a background `:sync` > Date: 2026-07-11 · Build at time of failure: `07-11 18:02Z @229c259-dirty` -> Status: **Safety net shipped** (paints are non-fatal, the appliance no longer -> bricks) — pending hardware re-test. **Root cause not yet eradicated**: a paint -> that lands during a sync still fails and drops the frame; the permanent fix (a -> persistent internal DMA scratch buffer) is specced below and tracked in the -> follow-ups. +> Status: **Safety net shipped and hardware-verified** (2026-07-13, during the +> [real-repo-sync kaizen](../kaizen/real-repo-sync.md): live scrolling through +> a real-repo push — the run-4 crash was this same paint-during-push family, +> and after the fixes the UI survived every subsequent push, success and +> failure alike). The paint path also **no longer allocates per repaint** +> (persistent two-frame `draw_into`/`swap` in `main.rs`, 2026-07-13), removing +> the frame-buffer half of the paint-time allocation. **Root cause not fully +> eradicated**: the EPD driver's per-refresh internal DMA scratch remains; the +> permanent fix (a persistent scratch buffer in `Epd`) is specced below and +> now tracked in [v0.9 robustness](../v0.9-robustness.md). > > Context: editor loop [`../../firmware/src/main.rs`](../../firmware/src/main.rs), > EPD driver [`../../firmware/src/epd.rs`](../../firmware/src/epd.rs), git @@ -156,9 +161,14 @@ triggered by the sync. - [x] Make all editor-loop paints non-fatal + `force_full` recovery (`main.rs`); release build green. -- [ ] Reflash and hardware-verify the safety net against the repro (edit → +- [x] Reflash and hardware-verify the safety net against the repro (edit → `:sync` → scroll through the push): panel must recover, not freeze. + **Verified 2026-07-13** (real-repo-sync kaizen runs 5–9: concurrent + typing/scrolling through full pushes, no freeze; bonus fix — repaints no + longer allocate at all, closing the run-4 `Frame::new_white` OOM-abort + variant of the same failure). - [ ] Implement the persistent internal DMA scratch buffer in `Epd` (eradication - above) if the stale-during-sync window proves annoying in real use. + above) if the stale-during-sync window proves annoying in real use — + → tracked in [v0.9 robustness](../v0.9-robustness.md). - [ ] After eradication, confirm refreshes succeed *during* a push and drop the stale window entirely. diff --git a/docs/v0.5-palette-and-multi-file.md b/docs/v0.5-palette-and-multi-file.md index 689e3e7..7534232 100644 --- a/docs/v0.5-palette-and-multi-file.md +++ b/docs/v0.5-palette-and-multi-file.md @@ -170,11 +170,13 @@ apply to them. **TODO (on-device, next time the device is on the bench)** — two measurements from the same boot log, both already instrumented: -- [ ] **Re-measure the walk time** after the d_type fix (`2660a3e` — dirent +- [x] **Re-measure the walk time** after the d_type fix (`2660a3e` — dirent `file_type()` instead of a per-entry `metadata()` stat, which cost - ~32 ms/file and made run 1 take 35 s for 1098 files). Read the - `file walk: N files in Xms` line. Only if it's still slow does the - async-walk idea come back on the table. + ~32 ms/file and made run 1 take 35 s for 1098 files). **Measured + 2026-07-13: 1098 files in 4.3 s** (~4 ms/file, readdir-over-SPI bound — + 8× under the stat-per-entry cost, but boot cursor-ready is now ~8.7 s, + so the async-walk question is back open; it now lives with the + [v1.0 ≤ 3 s boot item](v1.0-polish.md)). - [ ] **Read the file-list DRAM cost** from the new `file list: internal heap -> ( KB consumed)` line (the build is bracketed with `MALLOC_CAP_INTERNAL` readings in diff --git a/docs/v0.7-search-and-git.md b/docs/v0.7-search-and-git.md index 6213b24..96c7c6f 100644 --- a/docs/v0.7-search-and-git.md +++ b/docs/v0.7-search-and-git.md @@ -12,3 +12,17 @@ fast-forward is still to build. Search not started. surface it (renamed from the planned `:Gpull`). Editor command + `Effect::Pull` done 2026-07-11 (host-tested); the git-thread fetch/fast-forward in `git_sync` remains (only push is wired today). + +Sync performance — inherited from the +[real-repo-sync kaizen](kaizen/real-repo-sync.md) (closed 2026-07-13 at +24.1 s end-to-end; target ≤ ~10 s): + +- [ ] Close the publish gap: 19.8 s today — the splice's 5.0 s and the ~7 s of + repo-open/negotiation overhead are the next curves + ([tradeoff analysis](tradeoff-curves/sync-commit-staging.md)). +- [ ] Instrument the residual ~360 ms/loose-write (suspect: FAT directory-op + cost in the freshen/refresh path) — one `sd_bench` + `p_mmap`-miss + logging pass. +- [ ] The images-off-card lever + ([notes/git-sync-images-and-repo-size.md](notes/git-sync-images-and-repo-size.md)) + composes with the splice — decide whether to take it here. diff --git a/docs/v0.9-robustness.md b/docs/v0.9-robustness.md index 1e6c25a..3bc523c 100644 --- a/docs/v0.9-robustness.md +++ b/docs/v0.9-robustness.md @@ -5,8 +5,22 @@ **Status:** not started. -- [ ] Crash-safe writes (write to `.tmp`, fsync, rename) -- [ ] Recover from interrupted push (re-attempt on next save) +- [ ] Crash-safe writes (write to `.tmp`, fsync, rename) — NB FatFS `f_rename` + refuses to overwrite, so it's unlink-then-rename + `*.tmp` boot-recovery + (found in [Spike 3](postmortems/2026-07-05-spike3-sd-cmd59.md), still + open there) +- [ ] Recover from interrupted push (re-attempt on next save) — the splice + journal + stranded-commit recovery (2026-07-13) already survive a + power-pull mid-push; this item is the *retry* half +- [ ] Reconnect-on-stale-connection in the libgit2 http/stream layer — the + push keep-alive race is **avoided, not fixed** (repack keeps the marking + phase at ~3.5 s ≪ the ~30 s idle window; a multi-pack or cold-cache + state could still lose it — see the + [real-repo-sync kaizen](kaizen/real-repo-sync.md)) +- [ ] Eradicate the paint-during-sync DMA allocation failure: persistent + internal DMA scratch in `Epd` (safety net + allocation-free repaints + shipped; see the + [editor-freeze postmortem](postmortems/2026-07-11-editor-freeze-spi-dma-oom-during-sync.md)) - [ ] SD card removal / reinsert handling - [ ] Wi-Fi reconnect with backoff - [ ] On-device provisioning + settings screen: SSID, PAT rotation, default diff --git a/docs/v1.0-polish.md b/docs/v1.0-polish.md index 9d40a27..91ab131 100644 --- a/docs/v1.0-polish.md +++ b/docs/v1.0-polish.md @@ -5,8 +5,12 @@ **Status:** not started. -- [ ] Boot time ≤ 3 s to usable cursor — currently ~4.26 s; the ~1.9 s cold-boot - full refresh is a hard e-ink floor, so ≤ 3 s is marginal (see +- [ ] Boot time ≤ 3 s to usable cursor — 4.26 s at v0.1 ship; **regressed to + ~8.7 s on a real 1098-file card** once the v0.5 palette walk joined the + boot path (4.3 s of readdir-over-SPI, already d_type-optimised — see the + [v0.5 walk amendment](v0.5-palette-and-multi-file.md)), so the walk must + go async/deferred, and the ~1.9 s cold-boot full refresh + ~0.74 s PSRAM + memtest are the remaining levers (see [`notes/boot-time-budget.md`](notes/boot-time-budget.md)) - [ ] Font selection (at least one serif + one mono) with adjustable font size, switchable at runtime and persisted across reboots