aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcirakg <cirakg@cirakg.xyz>2026-10-26 15:01:52 +0100
committercirakg <cirakg@cirakg.xyz>2026-10-28 00:03:01 +0100
commite5172350151043050098d37b728054eb2e2be9f8 (patch)
treecd6a2d37c57f1fc728bdbaf942cfffde0e998372
parent86c11634379ab87238d794f8f9e8bbc991041e4d (diff)
docs(spike): test C split, only the backslash is refused
Settings spike test C, split (round 2, 2026-10-27, Android): Garmin Connect refuses to save only C3, the backslash. Every other character group and an Aegis export without backslashes save, and a real Aegis export imported on the Forerunner 70, so the import design stays. Android Aegis writes / as \/ (icons, names with a slash): the user guide explains replacing \/ with / or removing icons. C3 is a known limitation. The spike manifest gets a new application id: the old one could not be uploaded to the Garmin developer page. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
-rw-r--r--CHANGELOG.md6
-rw-r--r--README.md2
-rw-r--r--docs/SETTINGS_SPIKE.md20
-rw-r--r--docs/USER_GUIDE.md2
-rw-r--r--spike/settings/manifest.xml2
5 files changed, 28 insertions, 4 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 43fd4af..731ab87 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -47,6 +47,12 @@ All notable changes to this project are documented here. The format follows
"Require PIN" waiting), reading the change queue and a 4 KB code
replacement (also one queued by 0.9.0), at twice the work per step.
+### Documentation
+
+- Settings spike test C, split (`docs/SETTINGS_SPIKE.md`): every character
+ group and a complete unencrypted Aegis export save in Garmin Connect, so
+ Aegis JSON import works as designed.
+
## [0.9.0] - 2026-10-25
Fixes from the first real-watch test on the Forerunner 70 (2026-10-21) and
diff --git a/README.md b/README.md
index 7588ed2..72617a7 100644
--- a/README.md
+++ b/README.md
@@ -521,7 +521,7 @@ The full files are in `resources/settings/` (written in M7). `make lint` validat
- **Fields**: the eight import fields are joined in order. If the text is longer than one field accepts, continue in the next one.
- **Several syncs**: if the JSON is still incomplete after joining, the watch keeps what it got (encrypted under the device key) and reports: "Waiting for more: received 3,214 characters. Paste the next part into the import fields and turn 'Import now' on again." "Cancel pending import" discards it. The buffer is capped at 32 KB and expires after 24 hours. M5 measured an Aegis export at about 190 bytes per entry compact, and 400 to 500 pretty-printed. Exports larger than the cap need to be split into several imports.
- **Size reality**: pretty-printed Aegis JSON takes about 400 to 500 characters per entry without icons. Icons add several KB each and are the main reason a paste might not fit. An `otpauth://` URI takes about 80 to 200 characters.
-- **Spike results (M1, Android, 2026-10-21)**: one field carried 8000 characters and the eight together 64,000, so the 32 KB buffer, not Garmin Connect, limits one sync. `otpauth://` URIs with `&` save as they are. A test string mixing `< > \ " { } %`, accented letters and an emoji was refused by the phone; which character blocks it is being narrowed down (docs/SETTINGS_SPIKE.md). If `"` or `{ }` are refused, Aegis JSON can't be pasted and URIs are the import path.
+- **Spike results (M1, Android, 2026-10-21)**: one field carried 8000 characters and the eight together 64,000, so the 32 KB buffer, not Garmin Connect, limits one sync. `otpauth://` URIs with `&` save as they are. A test string mixing `< > \ " { } %`, accented letters and an emoji was refused by the phone. **Follow-up (round 2, SPIKE_DATE):** each character group saved on its own, and so did a complete unencrypted Aegis export, so Aegis JSON can be pasted into the import fields (docs/SETTINGS_SPIKE.md).
- **iPhone**: Garmin Connect on iOS reportedly rejects `&` (present in every URI with parameters) and `\` (used in JSON escapes). The spike ran on Android only. If it's confirmed on iOS, the parser also accepts `;` in place of `&`, and the user guide explains the workaround.
### 11.3 Parsing rules
diff --git a/docs/SETTINGS_SPIKE.md b/docs/SETTINGS_SPIKE.md
index a3e2328..a6eb736 100644
--- a/docs/SETTINGS_SPIKE.md
+++ b/docs/SETTINGS_SPIKE.md
@@ -69,7 +69,7 @@ Run on 2026-10-21 by the project owner with the Store beta of Settings Spike on
| 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 |
+| 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. The follow-up below split it: only the backslash `\` is refused; every other group and an Aegis export without backslashes save |
| 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 |
@@ -83,6 +83,24 @@ Run on 2026-10-21 by the project owner with the Store beta of Settings Spike on
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`.
+Results (2026-10-27, Android, the same phone and watch as above):
+
+| String | Characters | Saved and arrived |
+| --- | --- | --- |
+| C1 | `%` | Yes |
+| C2 | `< >` | Yes |
+| C3 | `\` | **No: the phone refused to save it** |
+| C4 | `"` | Yes |
+| C5 | `{ }` | Yes |
+| C6 | `ä ö ü ß €` | Yes |
+| C7 | emoji | Yes |
+| C8 | a JSON fragment | Yes |
+| aegis-json | a complete fake unencrypted Aegis export | Yes |
+
+The backslash alone blocks saving, which explains the `special` string. Aegis JSON can be pasted as long as it contains no `\`, so the import design (README 11) stays as it is: `otpauth://` links and unencrypted Aegis exports. The owner also imported a real Aegis export on the Forerunner 70 the same day.
+
+Aegis on Android writes JSON with Android's `org.json`, which escapes `/` as `\/`. A `/` appears in entry icons (base64 data and `"image\/png"`) and sometimes in a name or issuer; a `"` in a name is written as `\"`. Such an export is refused by the phone. Workarounds, in the user guide: replace every `\/` with `/` in a text editor (the JSON stays valid), remove the entry icons in Aegis before exporting, or paste `otpauth://` links instead. Test C3 is accepted as a known limitation; no fix is planned.
+
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
diff --git a/docs/USER_GUIDE.md b/docs/USER_GUIDE.md
index d351088..c9d4234 100644
--- a/docs/USER_GUIDE.md
+++ b/docs/USER_GUIDE.md
@@ -173,7 +173,7 @@ OTP Wallet never exports your secrets: they only flow into the watch. Your backu
- No unlocking with the watch's own passcode; the app has its own PIN.
- App settings only work with the Store version, which is why the app is a private beta rather than sideloaded.
- The phone shows what the watch writes back (Result fields, cleared forms, the About catalog) only after you reopen the settings.
- - Garmin Connect refuses to save some special characters in a text field. `otpauth://` links work; whether Aegis JSON (which needs `"`, `{` and `}`) can be pasted is still being tested ([SETTINGS_SPIKE.md](SETTINGS_SPIKE.md#follow-up-for-test-c)).
+ - Garmin Connect refuses to save text that contains a backslash `\` ([SETTINGS_SPIKE.md](SETTINGS_SPIKE.md#follow-up-for-test-c)). `otpauth://` links never contain one. Aegis on Android writes every `/` as `\/`, which happens in entry icons and in names with a `/`. If the phone refuses to save an Aegis export, replace every `\/` with `/` in a text editor (the file stays valid), or remove the icons in Aegis and export again, or use `otpauth://` links. A name with a `"` in it can only come over as an `otpauth://` link.
- **Import**
- Encrypted Aegis exports can't be decrypted on a watch (it would need 32 MiB of memory); export unencrypted.
- Google Authenticator export links aren't supported; mOTP and Yandex entries are skipped.
diff --git a/spike/settings/manifest.xml b/spike/settings/manifest.xml
index 3144ffa..0579915 100644
--- a/spike/settings/manifest.xml
+++ b/spike/settings/manifest.xml
@@ -9,7 +9,7 @@
* Products: the four test devices, including your Forerunner 70.
-->
<iq:manifest version="3" xmlns:iq="http://www.garmin.com/xml/connectiq">
- <iq:application id="9e455c06fab44b58b6d431a2d8cf2900" type="watch-app" name="@Strings.AppName"
+ <iq:application id="9e455c06fab44b98b6d431a2d8cf2900" type="watch-app" name="@Strings.AppName"
entry="SpikeApp" launcherIcon="@Drawables.LauncherIcon" minApiLevel="5.0.0">
<iq:products>
<iq:product id="fr255s"/>