lower Mk4 default wrap-around from 16 to 10 (same as Q)
What changed, and why it matters
This commit changes a user-interface preference on the COLDCARD Mk4 hardware wallet: how many menu items a list must have before the up/down keys wrap around from top to bottom. The threshold is lowered from 16 to 10, matching the Q model. It is a cosmetic/UX consistency change, not a security fix.
No security action required. Treat as a normal UX/consistency change during release review.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The patch updates the default menu wrap-around threshold in shared/menu.py from 16 (Mk4) / 10 (Q) to 10 for both devices. It also renames the setting labels in shared/flow.py from ‘Default Off’/’Enable’ to ‘Default’/’Always Wrap’, updates the changelog, and adjusts automated UI tests accordingly. No cryptographic, authentication, or firmware-integrity code is touched.
Changed components
shared/menu.pyshared/flow.pytesting/core_fixtures.pytesting/test_ux.pyreleases/Next-ChangeLog.mdInspect captured patch +13 / −11
diff --git a/releases/Next-ChangeLog.md b/releases/Next-ChangeLog.md
index 1227c42..ecb7296 100644
--- a/releases/Next-ChangeLog.md
+++ b/releases/Next-ChangeLog.md
@@ -29,7 +29,7 @@ This lists the new changes that have not yet been published in a normal release.
## 5.4.4 - 2025-09-1x
- Bugfix: Part of extended keys in stories were not always visible.
-
+- Change: Mk4 default menu wrap-around lowered from 16 to 10
# Q Specific Changes
diff --git a/shared/flow.py b/shared/flow.py
index 6c68784..c3c568b 100644
--- a/shared/flow.py
+++ b/shared/flow.py
@@ -186,9 +186,9 @@ The signed transaction will be named <TXID>.txn, so the file name does not leak
MS-DOS tools should not be able to find the PSBT data (ie. undelete), but forensic tools \
which take apart the flash chips of the SDCard may still be able to find the \
data or filenames.'''),
- ToggleMenuItem('Menu Wrapping', 'wa', ['Default Off', 'Enable'],
+ ToggleMenuItem('Menu Wrapping', 'wa', ['Default', 'Always Wrap'],
story='''When enabled, allows scrolling past menu top/bottom \
-(wrap around). By default, this only happens in very large menus.'''),
+(wrap around). By default, this only happens in menus whose length is greater than 10.'''),
ToggleMenuItem('Home Menu XFP', 'hmx', ['Only Tmp', 'Always Show'],
story=('Forces display of XFP (seed fingerprint) '
'at top of main menu. Normally, XFP is shown only when '
diff --git a/shared/menu.py b/shared/menu.py
index 98f3f0b..ccaa9e5 100644
--- a/shared/menu.py
+++ b/shared/menu.py
@@ -331,9 +331,8 @@ class MenuSystem:
if wrap: return True
# Do wrap-around (by request from NVK) if longer than the screen itself (on Q),
- # for mk4, limit is 16 which hits mostly the seed word menus.
- limit = 10 if has_qwerty else 16
- return self.count > limit
+ # Mk4: same limit
+ return self.count > 10
def down(self):
if self.cursor < self.count-1:
diff --git a/testing/core_fixtures.py b/testing/core_fixtures.py
index 38e88fc..1964bbb 100644
--- a/testing/core_fixtures.py
+++ b/testing/core_fixtures.py
@@ -55,7 +55,7 @@ def _dev_hw_label(device):
def _pick_menu_item(device, is_Q, text):
print(f"PICK menu item: {text}")
- WRAP_IF_OVER = 16 # see ../shared/menu.py .. this is larger of 10 or 16
+ WRAP_IF_OVER = 10 # see ../shared/menu.py
_need_keypress(device, KEY_HOME if is_Q else "0")
m = _cap_menu(device)
diff --git a/testing/test_ux.py b/testing/test_ux.py
index d7d229f..e0cfcc7 100644
--- a/testing/test_ux.py
+++ b/testing/test_ux.py
@@ -715,11 +715,14 @@ def test_destroy_seed(goto_home, pick_menu_item, cap_story, press_select,
def test_menu_wrapping(goto_home, pick_menu_item, cap_story, cap_menu,
press_select, press_up, press_down, press_cancel,
- is_q1):
+ is_q1, settings_remove):
+ settings_remove("wa") # disable
goto_home()
# first try that infinite scroll is turned off
# home
- for i in range(10): # settings on 5th in home (10 is way past that)
+ assert len(cap_menu()) < 10
+
+ for i in range(10):
press_down()
# sitting at Logout
@@ -730,7 +733,7 @@ def test_menu_wrapping(goto_home, pick_menu_item, cap_story, cap_menu,
press_select()
pick_menu_item("Menu Wrapping")
press_select()
- pick_menu_item("Enable")
+ pick_menu_item("Always Wrap")
time.sleep(1)
press_cancel() # back to home menu
press_cancel() # at Ready To Sign
@@ -741,7 +744,7 @@ def test_menu_wrapping(goto_home, pick_menu_item, cap_story, cap_menu,
press_select()
pick_menu_item("Menu Wrapping")
- pick_menu_item("Default Off")
+ pick_menu_item("Default")
time.sleep(1)
press_cancel() # back in home menu
press_cancel() # at Ready To Sign
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.