Skip to content

Commit 6656cd3

Browse files
committed
fix: retain failed ride recordings
1 parent dd5760d commit 6656cd3

8 files changed

Lines changed: 517 additions & 23 deletions

File tree

‎.github/workflows/release.yml‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ jobs:
3535
run: python3 tools/test_notes_io.py --compiler cc
3636
- name: Test ride history storage
3737
run: python3 tools/test_ride_history.py --compiler cc
38+
- name: Test ride recording
39+
run: python3 tools/test_ride_recording.py --compiler cc
3840
- name: Test Ring history storage
3941
run: python3 tools/test_ring_history.py --compiler cc
4042
- name: Test ebook pages
@@ -161,6 +163,21 @@ jobs:
161163
if-no-files-found: warn
162164
retention-days: 14
163165

166+
- name: Retain ride recording evidence
167+
uses: actions/upload-artifact@v4
168+
if: always()
169+
with:
170+
name: ride-recording-logs
171+
path: |
172+
build/ride-recording/compile.log
173+
build/ride-recording/result.log
174+
build/ride-recording/source.json
175+
build/ride-recording/ride_recording.inc
176+
build/ride-recording/ride_recording_config.inc
177+
build/ride-recording/storage_source.inc
178+
if-no-files-found: warn
179+
retention-days: 14
180+
164181
- name: Retain Ring history test evidence
165182
uses: actions/upload-artifact@v4
166183
if: always()

‎ROADMAP.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ Phase 1 software progress is also underway:
6868
- [x] Notes and ride summaries use recoverable backup replacement; rides publish only after durable sync, and health logs repair incomplete final rows.
6969
- [x] Notes loads complete files up to 65,535 bytes, replacing a silent 2,047-byte prefix. Recovery/read/close errors, oversized files and NUL data disable Save; byte-length and SD checks run before storage changes. Its launcher leave hook clears editor ownership. Four preceding-source controls reproduce full-note truncation; 36 native file/fault cases and five real LVGL cases pass, including maximum ASCII/UTF-8 notes and 25 reopens without retained resources in the unchanged 96 KiB pool. Linux and Windows CI retain separate source-bound evidence. Physical SD/panel and power cuts remain open.
7070
- [x] Ride history reports recovery/open/read/close errors as unavailable instead of showing zero or partial totals. Summary appends check SD availability and preparation errors, reject failed read chunks before copying, and retain the first error through cleanup. All 50 native file/fault cases pass; the preceding callbacks fail 24 controls. Exact final/backup/temporary bytes and 25 reopens are checked with closed modeled handles. Linux CI retains source hashes and logs, and the unflashed firmware builds with unchanged configuration. Physical SD/panel and power cuts remain open.
71+
- [x] Ride Start checks both directories, stops on noncollision creation errors and preserves their first cause. Rejected headers/rows, periodic sync failures and known SD loss retain the named TMP and clear recording ownership without retrying publication. All 39 native recording/history/storage cases pass; the preceding source fails 27 controls. Exact CSV/index/backup bytes, 100-name limits, tick wrap and 25 same-second restart pairs are checked with closed streams/descriptors. Linux CI retains source hashes and logs. Physical SD, BLE, panel and power cuts remain open.
7172
- [x] Ring logging commits its saved timestamp only after tail recovery and a complete, successfully closed read. Failed loads retain queued samples and defer history requests until a successful retry; known SD unavailability also blocks a cached checkpoint. Appends check directory errors and preserve the first seek/tell/header/row error through close and repair. All 59 native file/queue/fault cases pass; the preceding callbacks fail 32 controls. Checks verify exact bytes, retry/deduplication, timeout handling while blocked and 25 checkpoint reopens with closed modeled handles. Linux CI retains source hashes and logs. Physical SD, BLE, panel and power cuts remain open.
7273
- [x] Ebook page reads publish their text and byte positions only after read/close success. Failed navigation retains the previous page for retry, including zero-byte and full-count read errors. Initial navigation is disabled until a page loads; callbacks reject disabled/offscreen actions and invalid positions. All 44 native file/state/fault checks pass, including 25 navigation cycles with one reused buffer and closed handles. Thirty-one preceding-callback controls fail; three new unsafe-boundary guards are tested only with the new callbacks. Linux CI retains source hashes, initialization source and logs. Physical SD/panel and power behavior remain open.
7374
- [x] Recognized Scope/I2C and saved serial CSV loads require a successful close before showing a graph or row-copy controls. Failed or empty capture loads release their row buffer immediately. All 36 real LVGL/native-file checks pass; the preceding viewers fail 15 controls. Checks cover both row limits, I2C gaps, read/seek/close and allocation faults, unchanged file/clipboard bytes and 25 success/error/reopen cycles per viewer with stable memory in the unchanged 96 KiB pool. Existing serial-copy/inspector checks pass. Windows CI retains complete viewer/parser sources and logs; physical SD/panel behavior remains open.

‎docs/architecture.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,8 @@ Notes uses a temporary PSRAM buffer to load an entire file of up to 65,535 bytes
8989

9090
Ride history shows totals only after recovery, reading and closing the summary succeed; a missing index is valid empty history. Storage errors display an unavailable message and update the shared SD error. Appending checks known SD availability, directory creation and temporary-file removal before copying. A failed read chunk is rejected before writing, and the first read/write/open error survives source/destination close and temporary cleanup failures. The existing replacement helper still owns sync, backup, publication and rollback. Native tests verify exact file bytes and closed modeled handles; physical FAT/SD and panel behavior remain open.
9191

92+
Ride recording checks both directories and advances through its 100 same-second names only on CSV/TMP collisions. Other creation errors stop Start; a failed stream conversion closes its descriptor and attempts to remove the newly created empty TMP. Rejected headers/rows and periodic sync failures use one abort path that closes recording ownership, retains the TMP and reports the captured first cause. Tick and Stop also abort on known SD loss before another row or publication. Healthy Stop commits the CSV before rebuilding history, so an index failure leaves the published ride authoritative. Native tests compile the actual lifecycle and history helpers together with storage; UI, BLE data, time and SD boundaries are controlled.
93+
9294
Ring's saved heart-rate timestamp becomes loaded only after incomplete-tail repair, seek/size checks, the expected bounded tail read and close succeed. Read or close errors leave the checkpoint unchanged and retryable. Its existing health timer retains queued samples and defers history requests until that load succeeds, then filters timestamps against the recovered checkpoint. Known SD unavailability blocks queue processing even when a checkpoint is cached; timeout state still advances before the storage gate. Appends preserve the first error through close and tail repair. Native files and controlled queue/timer/SD boundaries verify this behavior; physical SD, BLE and scheduling remain open.
9395

9496
Ebooks reads up to 8 KiB into its existing cached PSRAM buffer. Page text, current/next byte positions, navigation state and scroll position change only after successful seek, read and close. Failure preserves the confirmed page and positions, reports the first error and allows retry when storage is available. Reader initialization clears both offsets and disables navigation until loading succeeds. Callbacks recheck disabled state and screen pointers; negative positions and additions beyond the platform's `long` range are rejected. Native files and controlled UI/heap/SD boundaries verify the transitions; physical SD and panel behavior remain open.

‎docs/data-formats.md‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ Tab5 OS keeps user-owned documents and logs on the removable microSD card. Built
77
| Data | Path | Publication rule |
88
| --- | --- | --- |
99
| Note | `/DOCS/NOTE.TXT` | Written through `NOTE.TMP`; the previous complete note is retained as `NOTE.BAK`. |
10-
| Ride samples | `/RIDES/YYMMDD/HHMMSSNN.CSV` | Recorded as `.TMP` and renamed to `.CSV` only after flush, media sync, and close succeed. `NN` is `00`-`99` for same-second collisions. |
10+
| Ride samples | `/RIDES/YYMMDD/HHMMSSNN.CSV` | Recorded as `.TMP`, synced every ten seconds, and renamed to `.CSV` only after flush, media sync, and close succeed. `NN` is `00`-`99` for same-second collisions. |
1111
| Ride index | `/RIDES/SUMMARY.CSV` | Rebuilt through `SUMMARY.TMP`; the previous index is `SUMMARY.BAK`. The individual ride CSV is authoritative. |
1212
| Heart rate | `/HEALTH/HR.CSV` | Append-only rows; an incomplete final row is discarded before later data is read or appended. |
1313
| I2C watch | `/I2C/YYMMDD/HHMMSSNN.CSV` | Logged at 1 Hz as `.TMP`, synced every ten seconds, and renamed only when capture stops successfully. |
@@ -21,6 +21,8 @@ Tab5 OS keeps user-owned documents and logs on the removable microSD card. Built
2121

2222
Files ending in `.TMP` are unpublished: they may be incomplete after power loss, or fully synced but retained because publication failed. They must not be reported as finished captures without validation. A `.BAK` file is the previous complete generation and can be used for recovery when its corresponding final file is absent.
2323

24+
Ride Start stops on directory/stat/open/stream-creation errors and retries only occupied CSV/TMP names; exhausting all 100 names reports `EEXIST`. Failed stream creation attempts to remove its newly created empty TMP. Rejected headers/rows, periodic sync failures and known SD loss close recording ownership and retain the named TMP without a publication retry. The first error survives cleanup; absent errno falls back to `EIO`. Restart skips retained files. A healthy Stop publishes the ride CSV before updating its index, so an index-update failure does not invalidate the saved CSV. Native byte/fault checks do not prove physical SD durability or power-loss recovery.
25+
2426
Notes edits complete text files of at most 65,535 bytes. A missing note starts an empty draft; a missing final note can be restored from `NOTE.BAK`. Recovery, open, read or close failures disable editing and Save until a successful reopen. Oversized files and files containing NUL bytes also disable Save and keep their original bytes. Save checks the draft's byte length before changing any path, including for UTF-8 text whose character count is smaller than its byte count. Notes loads the complete text in bulk before applying the editor's character limit. Leaving Notes clears its editor pointer and Save permission. Native files and LVGL checks verify these boundaries; physical SD removal, full-card and power-loss behavior remain hardware gates.
2527

2628
Ebooks reads at most 8,192 source bytes per page without changing the file. Open, seek, read and close failures preserve the last confirmed page and its byte positions; an error cannot become a successful partial page or `End of book`. Next/Prev can retry from the retained position once storage is available. Initial navigation stays disabled until loading succeeds, and callbacks reject disabled/offscreen actions. The existing text conversion and raw-byte paging remain unchanged. Native checks verify file bytes and controlled state/error handling; physical SD and panel behavior remain hardware checks.

‎docs/testing.md‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ Python 3 and Node.js are needed for the quick checks. The configuration checks a
1313
| Storage writes or incomplete CSV rows | [Core command reference](#core-command-reference), [CSV tail recovery](#csv-tail-recovery) and a firmware build. |
1414
| Notes loading, saving or lifecycle | [Notes storage and UI](#notes-storage-and-ui) and a firmware build. |
1515
| Ride history loading or summary appends | [Ride history storage](#ride-history-storage) and a firmware build. |
16+
| Ride Start, periodic recording or Stop | [Ride recording](#ride-recording) and a firmware build. |
1617
| Ring heart-rate logging, saved timestamps or queue processing | [Ring history storage](#ring-history-storage) and a firmware build. |
1718
| Ebook page loading or navigation | [Ebook pages](#ebook-pages) and a firmware build. |
1819
| Ebook library enumeration | [Ebook library](#ebook-library) and a firmware build. |
@@ -132,6 +133,20 @@ The preceding callbacks fail 24 controls, including misleading totals after reco
132133

133134
Generated callbacks/storage source, full main/function/storage/header/test hashes and compile/result logs stay under `build/ride-history/`. Linux CI runs the fixture and retains these files as `ride-history-logs`, including diagnostics when compilation or execution fails. Its 50 cases are separate from the Windows native total.
134135

136+
## Ride recording
137+
138+
```powershell
139+
python tools/test_ride_recording.py --compiler 'C:/path/to/clang.exe'
140+
```
141+
142+
This portable fixture compiles eight actual recording, button, tick and history functions from `main/main.c` with the complete `storage_io.c`. Its 39 cases use native files, directories and descriptors to check exact ride CSV, summary and backup bytes, creation errors, header/row failures, periodic flush/sync, Stop failures, known SD loss, mixed collisions, all 100 occupied names, tick wrap, admission gates and restart after a rejected header. The 25-pair recovery case preserves both generations within each pair and checks closed streams and descriptors before removing owned files between pairs.
143+
144+
The preceding source fails 27 controls: ignored root-directory errors, stale or missing error causes, retry after a stream-creation failure, deleted partial headers and continued recording/publication after known SD loss. Failed writes retain a named TMP and preserve their first cause through close and SD error reporting. A later Stop cannot publish an aborted recording. A successful CSV remains authoritative when updating its history index fails; that failure is reported separately.
145+
146+
UI labels, BLE sensor caches, clocks/ticks, logical paths, SD admission/error reporting and I/O faults are controlled. The fixture seeds the ride root and an existing summary before each case; the real Start creates the date directory on its first successful run. UTC fixes filenames, and Windows descriptors use binary mode for SDK LF bytes. These checks do not execute BLE, real LVGL, SDK mount/error filtering, physical FAT/SD, the panel or power cuts. A retained TMP can contain partial or complete-looking bytes without confirmed physical durability.
147+
148+
Full main/function/storage/header/test hashes, generated function/config/storage source and compile/result logs stay under `build/ride-recording/`. Linux CI retains `ride-recording-logs`, including available failure diagnostics. These 39 cases are separate from the Windows native total and the 50 ride-history cases.
149+
135150
## Ring history storage
136151

137152
```powershell

0 commit comments

Comments
 (0)