aboutsummaryrefslogtreecommitdiff
path: root/docs/SETTINGS_SPIKE.md
blob: a3e23282a0b6ab4a2ee7a97b37a59e16c93316a5 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
<!--
  Author:  cirakg & claude ai
  Summary: Milestone M1: how to run the settings spike on your phone and Forerunner 70, and where to record the results.
-->
# Settings spike (M1)

Garmin doesn't document how long a text setting may be, which characters the Garmin Connect app accepts, or whether values written by the watch show up on the phone. The inbox and import design (README sections 10 and 11) depends on those answers, so this milestone measures them with a small throwaway app, **Settings Spike**, on your Android phone and Forerunner 70.

It takes about 30 minutes. Everything uses fake test strings; never paste a real secret here.

## What the spike app does

- Its settings have eight text fields with no length limit, one password field, a read-only status field, a switch, a list, a number and a long number.
- On the watch it shows, for each text field: the length in characters and bytes, the first 12 and last 8 characters, and which of `& < > \ " { } %` and non-ASCII characters arrived.
- Each time you save settings while the app is open, it counts the change, writes `seen N chars at HH:MM:SS, change #K` into the read-only status field, and clears the password field. That tests whether the phone shows values the watch wrote.
- Scroll with UP/DOWN or by swiping; START or a tap jumps back to the top.

The test strings make cuts obvious: each starts with `N=<length>|`, has a marker `P<position>` every 50 characters, and ends with `END`. If the watch shows a different length or no `END`, the phone app cut the string; the last marker visible tells roughly where.

## Step 1: build the package (on your computer)

```sh
make spike
```

The file to upload is `build/spike/settings-spike.iq`. The spike has its own app ID, separate from OTP Wallet, so it can be deleted afterwards without affecting the real app.

## Step 2: a Garmin developer account and the beta upload

1. Open https://developer.garmin.com/connect-iq/ in a browser and sign in with your normal Garmin account. Accept the Connect IQ developer agreement if asked (the same agreement `make sdk` showed you).
2. Go to the developer dashboard (the "Upload an app" / "My apps" area of the Connect IQ developer site).
3. Upload `build/spike/settings-spike.iq` as a **new app** and tick **Beta App**. Fill in what the form requires (name "Settings Spike", any short description, any category). A beta app is visible only to your account.
4. Wait until the upload shows as available (usually minutes).

Garmin changes these pages from time to time; if a label differs, look for "beta" in the upload form.

## Step 3: install it on the Forerunner 70

1. On the phone, open the Connect IQ Store app (or Connect IQ inside Garmin Connect) while signed in to the same account.
2. Find **Settings Spike** among your apps (or open the beta's store link from the developer dashboard on the phone) and install it on the Forerunner 70.
3. On the watch, start **Settings Spike** from the apps list. It should show "Settings spike", "Changes seen: 0" and eight empty text fields.

## Step 4: get the test strings onto the phone

Copy `spike/settings/test-strings/index.html` to the phone (for example email it to yourself, or copy it over USB) and open it in Chrome. Each string has a **Copy** button that tells you how many characters it copied. The same strings are also in `spike/settings/test-strings/*.txt` (copy only the last line of a file).

## Step 5: the tests

Keep the spike app open on the watch for tests A to H, except where a test says otherwise. Open the settings on the phone through Garmin Connect: the Forerunner 70, then Connect IQ apps (or Activities & Apps), then Settings Spike, then Settings. Save after each change and read the watch.

| Test | What to do | What to write down |
| --- | --- | --- |
| A. One long field | Paste the 100-character string into Text 1, save. Repeat with 255, 256, 500, 800, 801, 1000, 2000, 4000 and 8000 (always Text 1). | The longest length that arrives complete (length matches and ends with `END`). For the first one that fails: does the phone refuse to save, show an error, or cut it silently (then the length the watch shows)? |
| B. Total size | Put the longest string that worked in A into Text 1 to Text 8, save. If that fails, empty fields until it saves. | The largest total ("Total: N chars" on the watch) that saves, and what happens beyond it |
| C. Characters | Paste `special` into Text 2, save. | The "has:" line on the watch, and anything missing compared with the string (especially `&` and `\`) |
| D. Write-back | After any save, close the settings on the phone and open them again. | Does "Status written by the watch" show `seen ... change #N`? Is the password field empty? |
| E. Live changes | With the app open, change one field and save. Then close the app on the watch, change another field, save, and start the app again. | Does "Changes seen" increase while the app is open? After the restart, does the watch show the new value? |
| F. Password field | Type `fake1234` into the password field, save. | Does the watch show "got 8 chars"? When you reopen the settings, is the field masked, empty, or showing the text? |
| G. Timing | Use a stopwatch from tapping Save until the watch screen changes. | Seconds for a short string and for the longest that worked |
| H. Other types | Toggle the switch, pick option C, enter 0 and then 301 as the number, enter 9999999999 as the long number. | Values shown on the watch, and which inputs the phone rejects (and its message) |

## Results

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 | 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

- **A and B** set the number and size of the import fields (`impText1` to `impTextN`, README 10.2) and the multi-part import buffer (README 11.2). For example, if one field holds 4000 characters but the total stops at 8000, import uses two or three fields per sync and multi-part import for larger Aegis files.
- **C** decides whether `otpauth://` URIs can be pasted as they are on your phone and whether the parser needs the `;` fallback (README 11.2).
- **D** decides whether status messages and cleared secret fields are visible on the phone. The design works either way (forms are idempotent and results also show on the watch, README 10.3); this tells us which one you'll experience.
- **E and G** decide whether processing on `onSettingsChanged` is enough or whether the app must also process forms at every start (it will do both; this confirms it).
- **F** confirms what the password field protects (on-screen masking only).

## Cleaning up

When the results are recorded: uninstall Settings Spike from the watch (Connect IQ Store app or the watch's app settings), and delete the beta from the developer dashboard if you like. The spike's code stays in `spike/settings/` for reference.