docs: sweep sync follow-ups into their owning version docs
Kaizen/postmortem next-steps kept accumulating with no owner. Each item now lives in one version doc (v0.7 sync perf, v0.9 robustness, v1.0 boot) with the source docs linking there; the editor-freeze safety net is marked hardware-verified and the v0.5 walk re-measure closed at 4.3s.
This commit is contained in:
@@ -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).
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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 <before> -> <after> (<N> KB consumed)` line
|
||||
(the build is bracketed with `MALLOC_CAP_INTERNAL` readings in
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user