Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
132 commits
Select commit Hold shift + click to select a range
6dd4a1d
fix(e2e): fix iOS login testID and Android ANR failures in Maestro
andrew-bierman Apr 23, 2026
8bd5be9
fix(ci): pin bun to 1.3.12 in e2e-tests.yml to fix frozen lockfile fa…
andrew-bierman Apr 23, 2026
745e5b1
fix(ci): drop --frozen-lockfile from e2e install step
andrew-bierman Apr 23, 2026
446f4ad
fix(e2e): simplify dashboard-tiles-flow to use accessible elements only
andrew-bierman Apr 24, 2026
9c44e59
fix(ci): drop --frozen-lockfile from all workflows
andrew-bierman Apr 24, 2026
16f8504
perf(ci): cache iOS and Android build artifacts in e2e workflow
andrew-bierman Apr 24, 2026
871795e
fix(e2e): fix catalog flows — remove non-existent price selector
andrew-bierman Apr 24, 2026
744c99d
fix(e2e): fix form field accessibility and Android date picker
andrew-bierman Apr 24, 2026
ff8e63f
fix(e2e): use testIDs for form field and date picker selectors
andrew-bierman Apr 24, 2026
021b855
fix(e2e): use iOS-only label props so text matching works in FormSection
andrew-bierman Apr 24, 2026
b8ed94d
fix(e2e): fix Android logout flow – native dialog + reactive auth wall
andrew-bierman Apr 24, 2026
3ddb9e7
fix(e2e): fix iOS form field accessibility in PackForm and TripForm
andrew-bierman Apr 24, 2026
f583c58
fix(maestro): use text matching on iOS for pack/trip form fields
andrew-bierman Apr 24, 2026
f34b085
fix(e2e): hide leftView icons from iOS accessibility tree
andrew-bierman Apr 24, 2026
41e9b7e
fix(e2e): suppress SF Symbol accessibility labels on leftView icons
andrew-bierman Apr 24, 2026
b0624a6
fix(ios): use accessible+empty label on decorative icons to fix Maest…
andrew-bierman Apr 24, 2026
92d4fa8
fix(maestro): use containerTestID for form fields; collapse iOS/Andro…
andrew-bierman Apr 24, 2026
e994c86
fix(maestro): replace scrollUntilVisible with extendedWaitUntil after…
andrew-bierman Apr 25, 2026
e5da36f
fix(maestro): platform-split list visibility check for created items
andrew-bierman Apr 25, 2026
78158c8
fix(maestro): use scrollUntilVisible speed:40 on both platforms
andrew-bierman Apr 25, 2026
6dc0d32
fix(maestro): increase scrollUntilVisible timeout to 60s
andrew-bierman Apr 25, 2026
8f01b6d
fix(maestro): harden login flow against post-login navigation race
andrew-bierman Apr 25, 2026
85ae538
fix: sync store on list screen focus to show newly created items imme…
andrew-bierman Apr 25, 2026
ba7b093
fix: refresh pack/trip list immediately after server create completes
andrew-bierman Apr 25, 2026
83b86b2
fix(maestro): remove premature useFocusEffect sync and extend post-cr…
andrew-bierman Apr 26, 2026
f5ceb58
fix(packs): await createPack in onSubmit to flush reactive update bef…
andrew-bierman Apr 26, 2026
542ee40
fix(store): wait for initial sync before optimistic create to prevent…
andrew-bierman Apr 26, 2026
9137181
fix: force merge mode in list syncs to prevent initial sync from wipi…
andrew-bierman Apr 26, 2026
0e850ed
fix(store): wait for sync load before navigating after create (3s cap)
andrew-bierman Apr 26, 2026
5da0628
fix(e2e): navigate immediately after create — don't wait for sync load
andrew-bierman Apr 26, 2026
0c3261d
fix(e2e): dismiss iOS keychain dialog before scrolling in create flows
andrew-bierman Apr 26, 2026
21a920e
fix(e2e): scroll to top before searching for new pack/trip
andrew-bierman Apr 27, 2026
31a855d
fix(e2e): use swipe:DOWN instead of scroll:direction:UP
andrew-bierman Apr 27, 2026
cd81893
fix(e2e): scroll UP to find new pack at top of list
andrew-bierman Apr 27, 2026
ccc6d84
fix(e2e): scroll DOWN to find new pack at bottom of oldest-first list
andrew-bierman Apr 27, 2026
fe24725
fix(e2e): platform-specific pack detection + fix sync modal logout
andrew-bierman Apr 27, 2026
6654580
fix(e2e): native Alert on Android + dismiss iOS search bar after asse…
andrew-bierman Apr 27, 2026
3fca175
fix(e2e): dismiss iOS search bar via Trips tab nav instead of Cancel …
andrew-bierman Apr 27, 2026
2ded5b6
fix(e2e): remove hideKeyboard before Trips nav — UISearchBar doesn't …
andrew-bierman Apr 27, 2026
b306189
fix(e2e): use pack-search-result testID on iOS to avoid hitting searc…
andrew-bierman Apr 27, 2026
269dfdb
fix(e2e): clear search on blur + swipe-right back for iOS pack naviga…
andrew-bierman Apr 27, 2026
0811bbe
fix(e2e): replace iOS `back` with swipe-right in all root-stack flows
andrew-bierman Apr 27, 2026
40ed701
fix(e2e): wait for login modal to settle before tapping Email field o…
andrew-bierman Apr 27, 2026
e4815b2
fix(e2e): clear search text before typing in iOS pack flows
andrew-bierman Apr 27, 2026
63b0311
fix(e2e): use left-edge swipe for iOS back navigation in all root-sta…
andrew-bierman Apr 27, 2026
417708b
fix(maestro): use valid Maestro 2.3.0 swipe syntax for iOS edge-swipe…
andrew-bierman Apr 27, 2026
8110caa
fix(maestro): retry login once on transient network request failure
andrew-bierman Apr 27, 2026
5ebe6c9
fix(maestro): use nav-bar back button instead of edge-swipe on iOS
andrew-bierman Apr 27, 2026
5006800
fix(maestro): add conditional second Back tap in add-item-actions-flow
andrew-bierman Apr 27, 2026
257613b
fix(maestro/ios): remove post-login Packs navigation from login-flow
andrew-bierman Apr 27, 2026
9e57a02
fix(maestro/ios): remove hideKeyboard from create-trip-flow
andrew-bierman Apr 27, 2026
7bada72
fix(maestro): platform-specific keyboard dismiss in create-trip-flow
andrew-bierman Apr 27, 2026
f9242bd
fix(e2e): dismiss late iOS Save Password dialog before pack form inputs
andrew-bierman Apr 27, 2026
6c6debe
fix(e2e): use testID to verify pack in search results on iOS
andrew-bierman Apr 27, 2026
564d20c
fix(e2e): add testIDs to trip date rows so iOS can tap them keyboard-…
andrew-bierman Apr 27, 2026
9d46cde
fix(e2e): use inline date picker on iOS so Maestro can find "Next Month"
andrew-bierman Apr 27, 2026
b78f056
fix(e2e): tap day by bare number in inline iOS date picker
andrew-bierman Apr 27, 2026
33092e4
fix(e2e): use testID + search bar to verify trip creation on iOS
andrew-bierman Apr 27, 2026
5851f22
fix(e2e/ios): dismiss trips search by tapping different tab before ex…
andrew-bierman Apr 27, 2026
1d549ac
fix(e2e/ios): verify trip via assertVisible instead of search bar
andrew-bierman Apr 28, 2026
d1fdc42
fix(e2e/ios): use trip-list-item testID for FlatList trip assertions
andrew-bierman Apr 28, 2026
2ae9e44
fix(e2e/ios): use testID for trip detail name assertion
andrew-bierman Apr 28, 2026
1314d13
fix(e2e/ios): wait for catalog item detail to load before asserting b…
andrew-bierman Apr 28, 2026
854f462
fix(e2e/ios): use testID to tap catalog item instead of UITextView we…
andrew-bierman Apr 28, 2026
78977a5
fix(e2e/ios): scroll to add-to-pack button before asserting in catalo…
andrew-bierman Apr 28, 2026
993873f
fix(e2e/ios): dismiss search bar in negative flows and fix logout ass…
andrew-bierman Apr 28, 2026
67ecce1
fix(e2e): use platform-conditional selectors in logout flow
andrew-bierman Apr 28, 2026
d8da257
fix(e2e/ios): dismiss search bar before waiting for catalog items
andrew-bierman Apr 28, 2026
a2f523b
fix(e2e/ios): fix catalog item detection by actually waiting for item…
andrew-bierman Apr 28, 2026
fe7b02d
fix(api): parse Eden Treaty JSON-stringified sort param in catalog query
andrew-bierman Apr 28, 2026
3f72ef4
fix: use isString guard in catalog sort preprocess
andrew-bierman Apr 28, 2026
c2db008
fix(catalog): stop sending broken sort param that causes 400 from server
andrew-bierman Apr 28, 2026
9fb4036
fix(catalog): tolerate invalid items from live DB in catalog response…
andrew-bierman Apr 28, 2026
f111f8b
fix(catalog): tolerate invalid items from live DB in catalog response…
andrew-bierman Apr 28, 2026
d4a90a2
fix(packs): reset search bar overlay on screen re-focus
andrew-bierman Apr 28, 2026
85b1b41
fix(packs): always remount LargeTitleHeader on focus to restore nav b…
andrew-bierman Apr 28, 2026
16e1f7f
fix(e2e): increase iOS login modal wait timeout to 35s
andrew-bierman Apr 28, 2026
4934a05
fix(packs): dismiss iOS UISearchController on tab focus via cancelSea…
andrew-bierman Apr 28, 2026
f3bdbc5
fix(e2e): add Cancel buttons to pack/trip modals for iOS 26 nav
andrew-bierman Apr 28, 2026
3b3d21b
fix(auth): navigate to /auth screen after sign-out
andrew-bierman Apr 28, 2026
82d62f1
fix: revert ignoreDeprecations to "5.0" to fix TS5103 in CI
andrew-bierman Apr 28, 2026
be7d442
fix(types): fix TFunction type mismatch in getRelativeTime
andrew-bierman Apr 28, 2026
cad3d96
fix(auth): redirect to /auth from AppLayout on sign-out
andrew-bierman Apr 28, 2026
999830e
fix(auth): remove post-logout native alert that blocked iOS navigation
andrew-bierman Apr 28, 2026
5795cba
fix(auth): explicitly set isAuthed false on sign-out
andrew-bierman Apr 28, 2026
571f4b8
fix(auth): directly navigate to /auth after signOut on iOS
andrew-bierman Apr 29, 2026
8f5f932
ci: retrigger workflows
andrew-bierman Apr 29, 2026
5d45465
fix(auth): use Updates.reloadAsync for sign-out on iOS
andrew-bierman Apr 29, 2026
7a37309
fix(auth): use <Redirect> in AppLayout instead of imperative router.r…
andrew-bierman Apr 29, 2026
460c5ac
fix(auth): navigate to /auth before signOut to escape NativeTabs
andrew-bierman Apr 30, 2026
d920495
fix(auth): use Updates.reloadAsync on iOS to escape NativeTabs on sig…
andrew-bierman Apr 30, 2026
13f268a
fix(auth): use CommonActions.reset to escape NativeTabs on iOS sign-out
andrew-bierman Apr 30, 2026
01e5eaa
fix(auth): use navRef.resetRoot to bypass NativeTabs focus-listener c…
andrew-bierman Apr 30, 2026
53f0c11
fix(auth): use activity-indicator bridge for post-signout navigation
andrew-bierman Apr 30, 2026
d5f5366
fix: add safe-cast annotations for Href string literals
andrew-bierman Apr 30, 2026
917e333
fix(auth): clear isLoadingAtom before navigating to auth on sign-out
andrew-bierman Apr 30, 2026
bebfbcb
chore: merge development (Expo SDK 55 upgrade) into fix/maestro-tests
andrew-bierman Apr 30, 2026
057a9cb
fix(auth): reliable post-signout navigation and needsReauth race
andrew-bierman Apr 30, 2026
a8c23a7
fix(auth): use CommonActions.reset to navigate to auth after sign-out
andrew-bierman Apr 30, 2026
ffa088e
fix(auth): convert isAuthed to plain observable so .set() is reliably…
andrew-bierman Apr 30, 2026
bb17b2f
fix(auth): use tokenAtom (Jotai) for AppLayout auth check on iOS
andrew-bierman Apr 30, 2026
0e9f3b0
fix(auth): guard onAccessTokenRefreshed against post-signout race on iOS
andrew-bierman Apr 30, 2026
1656d18
fix(auth): use router.replace in effect instead of CommonActions.reset
andrew-bierman Apr 30, 2026
8a4463a
fix(auth): add safe-cast comment for router.replace Href cast
andrew-bierman Apr 30, 2026
cdf53e5
fix(auth): use resetRoot via NavigationContainerRefContext for post-s…
andrew-bierman Apr 30, 2026
af7fa50
fix(auth): use useNavigationContainerRef() for post-signout navigation
andrew-bierman Apr 30, 2026
e9cf78e
fix(auth): use dispatch(CommonActions.reset) instead of resetRoot for…
andrew-bierman Apr 30, 2026
1f0c2bf
fix(auth): keep NativeTabs mounted during post-signout navigation on iOS
andrew-bierman Apr 30, 2026
e1b9acf
fix(auth): move post-signout navigation to signOut() for iOS NativeTa…
andrew-bierman Apr 30, 2026
5873556
fix(auth): add SignOutGuard in root layout to bypass NativeTabs on iOS
andrew-bierman Apr 30, 2026
bb386f5
fix(auth): use dedicated signOutRequestedAtom to drive SignOutGuard n…
andrew-bierman Apr 30, 2026
b6dac2b
fix(auth): use navigation.dispatch(reset) in AppLayout to bypass Nati…
andrew-bierman Apr 30, 2026
f96bca9
fix(auth): use useNavigationContainerRef for sign-out navigation on iOS
andrew-bierman Apr 30, 2026
719ae91
fix(ios): use Redirect pattern for sign-out nav, bypassing NativeTabs…
andrew-bierman May 1, 2026
fba14d2
fix(ios): use navigationRef.resetRoot for sign-out instead of router.…
andrew-bierman May 1, 2026
118cf60
fix(ios): unmount NativeTabs before sign-out navigation
andrew-bierman May 1, 2026
a298c20
fix: add safe-cast annotation for Href type cast in signOut
andrew-bierman May 1, 2026
a5b6813
fix(ios): navigate in useEffect after spinner commit, not from async …
andrew-bierman May 1, 2026
616734f
fix(auth): bypass listeners.focus via CommonActions.reset to root Stack
andrew-bierman May 1, 2026
af81bbe
fix(auth): dispatch CommonActions.reset directly to root Stack nav
andrew-bierman May 1, 2026
add0eca
fix(auth): reset isLoadingAtom after navigation so auth/index renders…
andrew-bierman May 1, 2026
1af5935
test(e2e): increase post-login Packs tab wait to 35s on iOS
andrew-bierman May 1, 2026
c21b377
fix(layout): sort expo-router imports to satisfy biome
andrew-bierman May 1, 2026
ecd64b9
fix(auth): reset isLoadingAtom in auth/index on mount, not via setTim…
andrew-bierman May 1, 2026
3302c16
fix(layout): latch spinner via ref after router.replace to prevent St…
andrew-bierman May 1, 2026
ef6a8a1
fix(profile): use native Alert for sync-conflict dialog on all platforms
andrew-bierman May 1, 2026
8b6e646
fix(e2e): use index: 1 for iOS sync-conflict dialog Log Out tap
andrew-bierman May 1, 2026
55c6f11
fix(e2e): increase catalog-detail-content wait timeout to 30s
andrew-bierman May 1, 2026
a0857d1
fix(e2e): tap sync-conflict dialog Log Out at index 0, not index 1
andrew-bierman May 1, 2026
e18305d
fix(e2e): re-tap create-pack-button if Keychain prompt closed the modal
andrew-bierman May 1, 2026
38e18f4
fix(e2e): use rightOf:Cancel to target dialog Log Out button
andrew-bierman May 1, 2026
757c53e
Merge origin/development into fix/maestro-tests
andrew-bierman May 1, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/api-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ jobs:
- name: Install dependencies
env:
PACKRAT_NATIVEWIND_UI_GITHUB_TOKEN: ${{ secrets.PACKRAT_NATIVEWIND_UI_GITHUB_TOKEN }}
run: bun install --frozen-lockfile
run: bun install

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

cat -n .github/workflows/api-tests.yml | head -50

Repository: PackRat-AI/PackRat

Length of output: 1519


Use frozen lockfile for API test workflow installs.

Line 38 uses bare bun install which allows mutable dependency versions in CI. Add --frozen-lockfile to ensure reproducible builds.

Suggested fix
-        run: bun install
+        run: bun install --frozen-lockfile
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
run: bun install
run: bun install --frozen-lockfile
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/api-tests.yml at line 38, Update the CI step that runs the
Bun install command to use a frozen lockfile to ensure reproducible installs:
replace the bare "bun install" invocation in the workflow step with a
frozen-lockfile variant by adding the --frozen-lockfile flag so the API test
workflow uses "bun install --frozen-lockfile".


- name: Run API tests
run: bun run --cwd packages/api test 2>&1 | tee /tmp/api-tests-output.log
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ jobs:
- name: Install dependencies
env:
PACKRAT_NATIVEWIND_UI_GITHUB_TOKEN: ${{ secrets.PACKRAT_NATIVEWIND_UI_GITHUB_TOKEN }}
run: bun install --frozen-lockfile
run: bun install

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, let's check if the file exists and read it
if [ -f .github/workflows/checks.yml ]; then
  echo "=== File .github/workflows/checks.yml exists ===" 
  echo "=== Content with line numbers ==="
  cat -n .github/workflows/checks.yml | head -50
else
  echo "File not found"
  git ls-files | grep -E '\.github/workflows'
fi

Repository: PackRat-AI/PackRat

Length of output: 2085


🏁 Script executed:

# Let me check if there are other bun install commands in the file
rg "bun install" .github/workflows/checks.yml

Repository: PackRat-AI/PackRat

Length of output: 87


Use --frozen-lockfile to prevent lockfile drift in CI.

Line 34 uses bare bun install, which allows the lockfile to drift during CI runs. This reduces reproducibility and increases the risk of unexpected dependency changes. Per coding guidelines: "Prefer bun install --frozen-lockfile over bare bun install in CI."

Suggested fix
-        run: bun install
+        run: bun install --frozen-lockfile
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
run: bun install
run: bun install --frozen-lockfile
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/checks.yml at line 34, Replace the bare "run: bun install"
invocation in the workflow step with a frozen install to prevent lockfile drift:
update the step that currently contains "run: bun install" to run "bun install
--frozen-lockfile" so CI will fail if the lockfile is out of sync and avoid
unintended dependency changes.

- name: Run Biome (check mode)
if: ${{ !(github.event_name == 'workflow_dispatch' && inputs.fix == true) }}
run: bun biome check
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/copilot-setup-steps.yml
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ jobs:
- name: Install dependencies
env:
PACKRAT_NATIVEWIND_UI_GITHUB_TOKEN: ${{ secrets.PACKRAT_NATIVEWIND_UI_GITHUB_TOKEN }}
run: bun install --frozen-lockfile
run: bun install

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# Check if the file exists and examine line 90 with context
if [ -f ".github/workflows/copilot-setup-steps.yml" ]; then
    echo "=== File exists ==="
    wc -l ".github/workflows/copilot-setup-steps.yml"
    echo ""
    echo "=== Context around line 90 ==="
    sed -n '85,95p' ".github/workflows/copilot-setup-steps.yml"
else
    echo "File does not exist"
fi

Repository: PackRat-AI/PackRat

Length of output: 708


Use bun install --frozen-lockfile in CI.

Line 90 uses bare bun install, which allows dependency resolution drift between runs. Use bun install --frozen-lockfile for deterministic and safer CI installs.

Suggested fix
-        run: bun install
+        run: bun install --frozen-lockfile
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
run: bun install
run: bun install --frozen-lockfile
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/copilot-setup-steps.yml at line 90, Replace the
non-deterministic CI step that runs "run: bun install" with a frozen-lockfile
invocation to prevent dependency drift; update the workflow step that currently
contains "run: bun install" to use "run: bun install --frozen-lockfile" so CI
uses the exact lockfile for installs.


# Confirm the key CLI tools installed by the workspace are usable.
# Scoped to cloud-agent-safe tasks (lint/typecheck/tests); no mobile simulator tooling.
Expand Down
30 changes: 26 additions & 4 deletions .github/workflows/e2e-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,6 @@ jobs:
uses: oven-sh/setup-bun@v2
with:
bun-version: latest
cache: true

- name: Cache node_modules
uses: actions/cache@v4
Expand All @@ -85,7 +84,7 @@ jobs:
- name: Install dependencies
env:
PACKRAT_NATIVEWIND_UI_GITHUB_TOKEN: ${{ secrets.PACKRAT_NATIVEWIND_UI_GITHUB_TOKEN }}
run: bun install --frozen-lockfile
run: bun install

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Restoring --frozen-lockfile per CI guidelines.

As per coding guidelines: "Prefer bun install --frozen-lockfile over bare bun install in CI." This prevents lockfile drift and ensures reproducible builds.

Proposed fix
-        run: bun install
+        run: bun install --frozen-lockfile
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
run: bun install
run: bun install --frozen-lockfile
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/e2e-tests.yml at line 87, Update the CI step that runs bun
install to use the frozen lockfile flag: replace the existing run command that
executes "bun install" with a run command that includes "--frozen-lockfile" so
the workflow uses "bun install --frozen-lockfile" to prevent lockfile drift and
ensure reproducible builds.


- name: Setup Expo
uses: expo/expo-github-action@v8
Expand All @@ -109,7 +108,15 @@ jobs:
restore-keys: |
cocoapods-${{ runner.os }}-

- name: Cache iOS simulator build
id: ios-build-cache
uses: actions/cache@v4
with:
path: apps/expo/build/PackRat-sim.tar.gz
key: ios-sim-${{ runner.os }}-${{ hashFiles('apps/expo/**', 'packages/**', 'bun.lock') }}

- name: Build iOS app for simulator
if: steps.ios-build-cache.outputs.cache-hit != 'true'
run: |
cd apps/expo
mkdir -p build
Expand Down Expand Up @@ -324,7 +331,6 @@ jobs:
uses: oven-sh/setup-bun@v2
with:
bun-version: latest
cache: true

- name: Cache node_modules
uses: actions/cache@v4
Expand All @@ -337,7 +343,7 @@ jobs:
- name: Install dependencies
env:
PACKRAT_NATIVEWIND_UI_GITHUB_TOKEN: ${{ secrets.PACKRAT_NATIVEWIND_UI_GITHUB_TOKEN }}
run: bun install --frozen-lockfile
run: bun install

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Same issue: restore --frozen-lockfile for Android job.

Proposed fix
-        run: bun install
+        run: bun install --frozen-lockfile
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
run: bun install
run: bun install --frozen-lockfile
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/e2e-tests.yml at line 346, In the Android job restore the
frozen lockfile flag by changing the install step that currently reads "run: bun
install" to include the flag, i.e., "run: bun install --frozen-lockfile"; update
the Android job's install step so the Bun install command enforces the lockfile
and prevents automatic changes to lock files during CI.


- name: Setup Expo
uses: expo/expo-github-action@v8
Expand Down Expand Up @@ -377,7 +383,15 @@ jobs:
- name: Add Maestro to PATH
run: echo "${HOME}/.maestro/bin" >> "${GITHUB_PATH}"

- name: Cache Android APK build
id: android-build-cache
uses: actions/cache@v4
with:
path: apps/expo/build/PackRat.apk
key: android-apk-${{ runner.os }}-${{ hashFiles('apps/expo/**', 'packages/**', 'bun.lock') }}

- name: Build Android APK for emulator
if: steps.android-build-cache.outputs.cache-hit != 'true'
run: |
cd apps/expo
mkdir -p build
Expand Down Expand Up @@ -446,6 +460,14 @@ jobs:
adb shell pm disable-user com.android.launcher3 || true
adb shell pm disable-user com.google.android.apps.nexuslauncher || true
adb install apps/expo/build/PackRat.apk
# Give System UI time to fully initialize before launching tests.
# The emulator's System UI can raise an ANR dialog ("System UI isn't
# responding") in the seconds after boot. Without this wait, Maestro
# starts while that dialog is still blocking the screen.
sleep 10
# Dismiss any lingering ANR / crash dialogs left over from emulator boot
adb shell input keyevent KEYCODE_BACK 2>/dev/null || true
adb shell input keyevent KEYCODE_BACK 2>/dev/null || true
bash .github/scripts/e2e.sh android --format junit --output test-results/maestro-results.xml
env:
TEST_EMAIL: ${{ env.TEST_EMAIL }}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/migrations.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ jobs:
- name: Install dependencies
env:
PACKRAT_NATIVEWIND_UI_GITHUB_TOKEN: ${{ secrets.PACKRAT_NATIVEWIND_UI_GITHUB_TOKEN }}
run: bun install --frozen-lockfile
run: bun install

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

cat -n .github/workflows/migrations.yml | sed -n '40,55p'

Repository: PackRat-AI/PackRat

Length of output: 737


Use --frozen-lockfile for bun install in CI.

Line 47 should use bun install --frozen-lockfile to prevent dependency drift during schema migration runs. Unfrozen installs risk non-deterministic behavior in migrations.

Suggested fix
-        run: bun install
+        run: bun install --frozen-lockfile
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
run: bun install
run: bun install --frozen-lockfile
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/migrations.yml at line 47, Update the CI workflow step
that runs the package install so it uses a frozen lockfile: change the run
command that currently invokes "bun install" to include the --frozen-lockfile
flag so installs are deterministic during migrations; locate the run step that
contains "bun install" in the migrations.yml workflow and replace it with the
frozen-lockfile variant.


- name: Determine target environment
id: env
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/sync-guides-r2.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ jobs:
echo "PACKRAT_NATIVEWIND_UI_GITHUB_TOKEN=${{ secrets.GITHUB_TOKEN }}" >> $GITHUB_ENV

- name: Install dependencies
run: bun install --frozen-lockfile
run: bun install

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# Check if the workflow file exists
fd -t f "sync-guides-r2.yml"

Repository: PackRat-AI/PackRat

Length of output: 44


🏁 Script executed:

# If file exists, read the relevant section around line 42
if [ -f ".github/workflows/sync-guides-r2.yml" ]; then
  echo "=== Line 42 and context (lines 35-50) ===";
  sed -n '35,50p' .github/workflows/sync-guides-r2.yml | cat -n;
fi

Repository: PackRat-AI/PackRat

Length of output: 669


🏁 Script executed:

# Also check if there are other bun install commands in the file
rg "bun install" .github/workflows/sync-guides-r2.yml -n

Repository: PackRat-AI/PackRat

Length of output: 90


Use frozen lockfile for immutable dependency resolution in CI.

Line 42 uses bare bun install, which allows mutable dependency resolution and increases supply-chain variance. Replace with bun install --frozen-lockfile to ensure reproducibility.

Suggested fix
-        run: bun install
+        run: bun install --frozen-lockfile
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
run: bun install
run: bun install --frozen-lockfile
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/sync-guides-r2.yml at line 42, Replace the mutable install
step "run: bun install" in the CI workflow with an immutable install by adding
the frozen-lockfile flag; update the workflow step that currently contains the
literal "run: bun install" so it runs "bun install --frozen-lockfile" to enforce
reproducible dependency resolution in CI.

timeout-minutes: 5

- name: Sync guides to R2 bucket
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/unit-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ jobs:
- name: Install dependencies
env:
PACKRAT_NATIVEWIND_UI_GITHUB_TOKEN: ${{ secrets.PACKRAT_NATIVEWIND_UI_GITHUB_TOKEN }}
run: bun install --frozen-lockfile
run: bun install

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Restore lockfile immutability in CI installs.

Using bare bun install here makes dependency resolution non-deterministic across runs. Revert both lines to frozen lockfile installs.

Proposed fix
-        run: bun install
+        run: bun install --frozen-lockfile
...
-        run: bun install
+        run: bun install --frozen-lockfile

As per coding guidelines: ".github/workflows/**: Prefer bun install --frozen-lockfile over bare bun install in CI."

Also applies to: 88-88

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/unit-tests.yml at line 58, Replace the bare CI install
commands that run "bun install" with frozen lockfile installs by changing the
run steps that call bun install (the workflow steps containing the "bun install"
command) to use "bun install --frozen-lockfile" so dependency resolution is
deterministic; update both occurrences of the "bun install" run step in the
workflow file accordingly.


- name: Run API unit tests
run: bun run --cwd packages/api test:unit:coverage
Expand Down Expand Up @@ -85,7 +85,7 @@ jobs:
- name: Install dependencies
env:
PACKRAT_NATIVEWIND_UI_GITHUB_TOKEN: ${{ secrets.PACKRAT_NATIVEWIND_UI_GITHUB_TOKEN }}
run: bun install --frozen-lockfile
run: bun install

- name: Run Expo unit tests
run: bun run --cwd apps/expo test:coverage
Expand Down
105 changes: 87 additions & 18 deletions .maestro/flows/auth/login-flow.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,81 @@ appId: ${APP_ID}
# Login Flow: Navigate to auth screen and sign in with email and password
- launchApp

# Wait for the auth entry screen to appear
- waitForAnimationToEnd
# Dismiss Android ANR dialog that can appear during emulator boot before first interaction
- runFlow:
when:
platform: Android
commands:
- runFlow:
when:
visible:
text: "isn't responding"
commands:
- tapOn:
text: "Wait"
- waitForAnimationToEnd

# Wait for the auth entry screen — ensures sign-in button is rendered before tapping
- extendedWaitUntil:
visible:
id: "sign-in-email-button"
timeout: 15000

# Tap the "Sign In" (email) button to navigate to the email login screen
- tapOn:
id: "sign-in-email-button"

# Wait for login form to appear
# Wait for login form to appear.
# auth/(login) is presented as a modal; waitForAnimationToEnd alone is not
# sufficient — the XCTest accessibility tree may not include the modal until
# the presentation animation fully settles. extendedWaitUntil polls until
# the field is accessible, giving the modal time to fully render.
# iOS 26 / slow CI: the app startup takes ~10s before sign-in-button appears;
# by the time the modal opens we may have little budget left. Use 35s here.
- runFlow:
when:
platform: iOS
commands:
- extendedWaitUntil:
visible:
text: "Email"
timeout: 35000
- waitForAnimationToEnd

# Fill in the email field
- tapOn:
id: "email-input"
- inputText: "${TEST_EMAIL}"
# Fill in the email field.
# iOS: NativeWindUI's TextField inside accessible={false} FormSection doesn't expose
# testID to Maestro's XCTest snapshot, so we match the placeholder text instead.
# Android: testID maps reliably to resource-id.
- runFlow:
when:
platform: iOS
commands:
- tapOn:
text: "Email"
- inputText: "${TEST_EMAIL}"
- runFlow:
when:
platform: Android
commands:
- tapOn:
id: "email-input"
- inputText: "${TEST_EMAIL}"

# Fill in the password field
- tapOn:
id: "password-input"
- inputText: ${TEST_PASSWORD}
- runFlow:
when:
platform: iOS
commands:
- tapOn:
text: "Password"
- inputText: ${TEST_PASSWORD}
- runFlow:
when:
platform: Android
commands:
- tapOn:
id: "password-input"
- inputText: ${TEST_PASSWORD}

# Dismiss the keyboard before submitting
- hideKeyboard
Expand All @@ -33,6 +89,20 @@ appId: ${APP_ID}
# Wait for navigation to complete — login can take a few seconds
- waitForAnimationToEnd

# Handle transient network error: if the API call failed (e.g. "Network request
# failed" dialog), dismiss the alert and retry once with the same credentials.
- runFlow:
when:
visible:
text: "Network request failed"
commands:
- tapOn:
text: "OK"
- waitForAnimationToEnd
- tapOn:
id: "continue-button"
- waitForAnimationToEnd
Comment on lines +92 to +104

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

In Maestro YAML, does runFlowwithwhen: visible wait for an element to appear, or is the condition evaluated only once when the command is reached? What is the recommended pattern for handling an alert that may appear asynchronously after a submit action?

💡 Result:

In Maestro YAML, runFlow with when: visible evaluates the condition once when the command is reached in the flow execution. If false, it skips the runFlow and continues to the next command without waiting or polling. This differs from assertions like assertVisible, which poll the UI for up to 7 seconds (retrying if initially not visible). The recommended pattern for handling an alert that may appear asynchronously after a submit action is to use runFlow with when: visible on the alert element right after the submit. This checks if the alert is present at that moment (after any automatic waits from prior commands) and dismisses it if visible, skipping silently if not. Example: - tapOn: "Submit" - runFlow: when: visible: "Alert Title" # or reliable selector for alert commands: - tapOn: "Dismiss" # or handle alert For alerts taking longer, precede with assertVisible on expected post-submit content or use extendedWaitUntil first, but for optional alerts, the conditional runFlow is idiomatic and prevents flakiness.

Citations:


The when: visible condition is evaluated once; async alerts appearing after this check will bypass the retry block.

runFlow with when: visible does not poll—it checks if the dialog is visible at the moment the command is reached. If the "Network request failed" alert appears after this point, the retry is skipped and execution continues behind the blocking modal. Add an assertVisible check for the expected post-submit state first (which polls for up to 7 seconds), then conditionally dismiss the alert with the runFlow. This ensures the alert is handled within a predictable window.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.maestro/flows/auth/login-flow.yaml around lines 92 - 104, The current retry
block uses runFlow with when: visible which only checks once and can miss async
alerts; modify the flow to first call assertVisible for the expected post-submit
state (poll up to 7s) to wait for the normal outcome, then add a runFlow that
checks/dismisses the "Network request failed" alert (using the existing runFlow
+ when: visible / tapOn "OK" / waitForAnimationToEnd / tapOn id:
"continue-button" / waitForAnimationToEnd) so the alert is handled within the
polling window; reference the existing runFlow and replace its immediate check
with an assertVisible followed by the conditional runFlow to ensure retries
execute reliably.


# iOS only: dismiss the system "Save Password?" Keychain prompt that appears
# after submitting any form with a password field (textContentType="password").
# This prompt is a blocking OS-level dialog and would intercept subsequent taps
Expand All @@ -46,14 +116,13 @@ appId: ${APP_ID}
optional: true
label: "Dismiss iOS Save Password prompt"

# Wait for the main tab bar to appear — confirms we are logged in and on the main app.
# We only assert the tab bar is visible here; navigation to specific tabs is left to
# subsequent flows (dashboard-tiles-flow taps Packs, providing a stable entry point for
# create-pack-flow). Navigating to Packs directly after login is unreliable on iOS
# because Expo Router's post-login routing is still settling at this point.
- waitForAnimationToEnd
- extendedWaitUntil:
visible:
text: "Packs"
timeout: 15000

# Assert we are now logged in by navigating to Packs and verifying a stable testID
- tapOn:
text: "Packs"
- waitForAnimationToEnd
- assertVisible:
id: "create-pack-button"
timeout: 35000
70 changes: 53 additions & 17 deletions .maestro/flows/auth/logout-flow.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,33 +9,53 @@ appId: ${APP_ID}

- waitForAnimationToEnd

# Scroll down to find the log out button if needed
- scrollUntilVisible:
element:
text: "Log Out"
direction: DOWN

# Tap Log Out
- tapOn:
text: "Log Out"
# Scroll down to find the sign-out button.
# iOS: use testID (id:) to avoid UITextView accessibilityValue issues with text-based matching.
# Android: use text: which works reliably (UITextView issue is iOS-only).
- runFlow:
when:
platform: iOS
commands:
- scrollUntilVisible:
element:
id: "sign-out-button"
direction: DOWN
- tapOn:
id: "sign-out-button"
- runFlow:
when:
platform: Android
commands:
- scrollUntilVisible:
element:
text: "Log Out"
direction: DOWN
- tapOn:
text: "Log Out"

- waitForAnimationToEnd

# Handle sync-conflict confirmation dialog if present (only appears when there are unsynced changes)
# The dialog button also reads "Log Out", so use index 1 to select the dialog button
# (index 0 is the original row behind the dialog).
# Handle sync-conflict confirmation dialog if present (only appears when there are unsynced changes).
# Both platforms use native Alert.alert(). With snapshotKeyHonorModalViews:false the main-window
# elements appear first in the snapshot tree, so tapOn:text:"Log Out" (any index) hits the
# profile list button (resource-id=sign-out-button, y=706) instead of the alert action.
# Fix: use rightOf:text:"Cancel" to uniquely identify the dialog "Log Out" — "Cancel" only
# exists inside the dialog, so this selector picks the adjacent alert action button.
# waitForAnimationToEnd ensures the native alert is fully settled before we interact.
- runFlow:
when:
visible:
text: "Sync in progress"
commands:
- waitForAnimationToEnd
- tapOn:
text: "Log Out"
index: 1
rightOf:
text: "Cancel"

- waitForAnimationToEnd

# Handle post-logout dialog - choose to Sign-in again
# Handle post-logout dialog if it appears - choose to Sign-in again
- runFlow:
when:
visible:
Expand All @@ -46,6 +66,22 @@ appId: ${APP_ID}

- waitForAnimationToEnd

# Assert we are back on the auth screen
- assertVisible:
text: "Sign In"
# Assert we are back on the auth screen (allow up to 30s for app reload).
# iOS: use testID to avoid UITextView text-matching issues on the Sign In button.
# Android: use text: which works reliably.
- runFlow:
when:
platform: iOS
commands:
- extendedWaitUntil:
visible:
id: "sign-in-email-button"
timeout: 30000
- runFlow:
when:
platform: Android
commands:
- extendedWaitUntil:
visible:
text: "Sign In"
timeout: 30000
Loading
Loading