aboutsummaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
Diffstat (limited to 'docs')
-rw-r--r--docs/PERFORMANCE.md17
-rw-r--r--docs/SETTINGS_SPIKE.md42
2 files changed, 45 insertions, 14 deletions
diff --git a/docs/PERFORMANCE.md b/docs/PERFORMANCE.md
index 4c35be6..0433457 100644
--- a/docs/PERFORMANCE.md
+++ b/docs/PERFORMANCE.md
@@ -27,6 +27,23 @@ The targets are in [README section 18](../README.md#18-performance-budgets). Thi
## Results
+### Forerunner 70, 2026-10-21 (real watch, debug build 0.8.0)
+
+The first numbers from the real watch, read from "Debug: benchmark" on the sideloaded debug build (docs/YOUR_STEPS.md part 4.2):
+
+| Value | Forerunner 70 | Simulator (M4/M8) | Note |
+| --- | --- | --- | --- |
+| TOTP, SHA-1 | 18 ms | under 1 ms | One code per timer event is far inside the watchdog |
+| TOTP, SHA-512 | 732 ms | 17.5 ms | About 40 times SHA-1, as the simulator ratio predicted. A list with several SHA-512 entries fills in about one per second; the detail screen shows the code within a second |
+| PBKDF2 | 2,000 iterations per second | about 12,000 | Exactly the lower bound in README 18, so setting a PIN calibrates to the 2,000-iteration floor and unlocking takes about 1 s |
+| Header reading | 0 entries in 1 ms | | The benchmark ran before the demo entries were added, so this says nothing yet |
+| Self-test | 292 ms | | The crypto known-answer tests at start-up of the debug build |
+| Memory at the benchmark | 179 of 763 KB (23 %) | 21 % at the first frame | Well under the 70 % budget |
+
+Other timings reported from the same session: settings saved on the phone reach the watch in about 1 second (settings spike, test G). The Member QR demo card took noticeably long on its first opening and about 1 second the second time; its progress display jumped to 90 % almost at once, which is fixed in the next version (the percentage now follows the work, not the phase count).
+
+What this means: unlocking stays at about 1 s because 2,000 iterations is also the minimum the app accepts. An attacker who copies the watch's storage still has to run those 2,000 iterations per guess, but on a PC that is microseconds, so the PIN protects mainly against someone holding the watch (lockout and the optional erase after 10 wrong PINs), not against an offline attack on a copied file system (docs/SECURITY.md).
+
### M8, 2026-10-21 (polish and release candidate, version 0.8.0)
- **Memory, Forerunner 255S (512 KB):**
diff --git a/docs/SETTINGS_SPIKE.md b/docs/SETTINGS_SPIKE.md
index 340670a..a3e2328 100644
--- a/docs/SETTINGS_SPIKE.md
+++ b/docs/SETTINGS_SPIKE.md
@@ -61,23 +61,37 @@ Keep the spike app open on the watch for tests A to H, except where a test says
## Results
-Fill this in (or tell me the values and I'll record them). Date, phone model, Garmin Connect app version (Settings, About) and the watch firmware help explain later differences.
+Run on 2026-10-21 by the project owner with the Store beta of Settings Spike on the Forerunner 70 and an Android phone. The two version numbers were reported as "2.50" and "18.32" without labels; the phone model wasn't recorded.
| Item | Result |
| --- | --- |
-| Date, phone, Garmin Connect version, watch firmware | |
-| A. Longest single field that arrives complete | |
-| A. What happens above that (refused / error / cut to N) | |
-| B. Largest total across the eight fields | |
-| C. Characters that didn't arrive or blocked saving | |
-| D. Status written by the watch visible on the phone (yes/no) | |
-| D. Password field empty after the watch cleared it (yes/no) | |
-| E. Changes arrive while the app is open (yes/no) | |
-| E. Changes arrive while the app is closed, seen at next start (yes/no) | |
-| F. Password field: arrives on the watch, masked on the phone (yes/no each) | |
-| G. Time from Save to the watch updating (short / longest) | |
-| H. Phone-side validation of the number fields (message) | |
-| Other observations | |
+| Date, phone, Garmin Connect version, watch firmware | 2026-10-21, Android phone, versions 2.50 and 18.32 (which is the app and which the firmware is to be confirmed) |
+| A. Longest single field that arrives complete | 8000 characters, the longest string tested |
+| A. What happens above that (refused / error / cut to N) | Not tested: no string longer than 8000 was tried |
+| B. Largest total across the eight fields | 64,000 characters (8 fields of 8000) saved and arrived complete |
+| C. Characters that didn't arrive or blocked saving | The phone **refused to save** the `special` string. An `otpauth://` URI with `&`, `?`, `=`, `:` and `@` saved and arrived. Which of `< > \ " { } %`, the accented letters, `€` or the emoji blocks saving is not known yet: see the follow-up below |
+| D. Status written by the watch visible on the phone (yes/no) | Yes: the phone shows the "seen ... change #N" line and its number goes up |
+| D. Password field empty after the watch cleared it (yes/no) | Yes |
+| E. Changes arrive while the app is open (yes/no) | Yes |
+| E. Changes arrive while the app is closed, seen at next start (yes/no) | Yes |
+| F. Password field: arrives on the watch, masked on the phone (yes/no each) | When the settings were opened again, the field was empty, because the watch clears it after every save (as in D). The "got N chars" line on the watch wasn't reported. The OTP Wallet secret fields, which use the same field type, worked in the real-watch test (YOUR_STEPS 5.2), so the field is usable |
+| G. Time from Save to the watch updating (short / longest) | About 1 second |
+| H. Phone-side validation of the number fields (message) | 301 is rejected by the phone and the settings can't be saved. The switch, list (option C, value 2) and the long number 9999999999 arrive (`switchField: true`, `listField: 2`) |
+| Other observations | None |
+
+### Follow-up for test C
+
+The `special` string mixes many characters, so its failure doesn't say which one the phone rejects. The test-string page now has eight short strings, one per character group (`C1` percent, `C2` angle brackets, `C3` backslash, `C4` double quote, `C5` braces, `C6` accented letters and `€`, `C7` emoji, `C8` a JSON fragment), and `aegis-json`, a complete fake unencrypted Aegis export with one entry. Paste each into Text 2 and save; note which ones the phone refuses. Regenerate the page with `python3 spike/settings/test-strings/make_test_strings.py`.
+
+This decides whether Aegis JSON can be pasted into the import fields at all (it needs `"`, `{`, `}` and sometimes `\`). If the phone refuses those characters, Aegis import goes back to the design table: the fallback is pasting `otpauth://` URIs, which are confirmed to work.
+
+### What the results change
+
+- **Import field size (A, B).** The import design assumed fields of a few hundred characters. One field takes at least 8000 characters and the eight together at least 64,000, so Garmin Connect is not the limit: the watch's 32 KB import buffer is (README 11.2). About 160 compact Aegis entries, or 60 to 80 pretty-printed ones, fit in one sync. The eight `impText` fields and multi-part import stay as they are.
+- **`otpauth://` URIs (C).** They paste as they are, so the parser doesn't need the `;` fallback for `&`.
+- **Write-back (D).** Status lines written by the watch (the forms' **Result** fields) and cleared secret fields show on the phone after reopening the settings.
+- **Processing (E, G).** Changes arrive within about a second while the app is open, and at the next start when it is closed. The app already processes forms on both paths.
+- **Number validation (H).** The phone enforces `min` and `max` itself, so the watch-side range checks are a second line of defence only.
## How the results feed the design