Shared macOS runner accumulates orphaned simulator entries (registry
present, data dir missing on disk) which fail run_tests with 'Unable
to boot device because it cannot be located on disk'. Clean up before
every test run instead of requiring manual simctl intervention.
LCEssentials 2.0.2 replaced request(url:params:method:headers:jsonEncoding:debug:)
with request(url:method:body:pathParams:headers:debug:timeoutInterval:networkServiceType:persistConnection:).
The pre-encoded params Data is now wrapped in RawBody to preserve the same
application/json Content-Type behavior that jsonEncoding: true used to set.
- Remove bitrise.yml (no longer used, replaced by Gitea Actions on
a native macos-build:host runner - Docker VM-based macos-ctl/
macos-release runners are dead per earlier session)
- test.yml: push-triggered on any branch except develop/release/main,
runs fastlane tests (coverage) instead of raw xcodebuild
- beta.yml: PR-to-develop triggered, builds + uploads to TestFlight;
drops the dead wake/sleep-macos-vm jobs, uses the archive-API
checkout workaround (see go-gitea/gitea#21819), points at the real
ci-build.keychain-db instead of the old ci-signing.keychain-db name
- release.yml removed: release/main run nothing automated per the
agreed branch flow, promotion is manual
- Fastfile: add a tests lane (coverage) so the workflow just calls
fastlane, matching LC Wallet's convention
Running 'xcodegen generate' to register a new test file reverted every
setting that lives in project.pbxproj but is missing or stale in
project.yml. Restored the file from its known-good state and re-added only
the four PublicStoreDistanceTests.swift references by hand.
What xcodegen had destroyed:
- TargetAttributes gained DevelopmentTeam = "" on the app, the extension
and the unit tests, which blanks the Team in Xcode's Signing UI so the
provisioning profile no longer resolves.
- APP_ATTEST_ENVIRONMENT = production removed entirely.
- NSLocationWhenInUseUsageDescription replaced with the English string from
project.yml, dropping the pt-BR one shipped for App Review.
- CURRENT_PROJECT_VERSION reset from 2026.0.25.0.0.1 to 1.
Verified the file now differs from the known-good state by exactly the four
new test-file lines, and that all four items above are back.
Guest browsing showed 'Distância indisponível' on every store card and a
'--' tile on store detail, because the public locator response carries no
distance and StoreSummary.init(publicItem:) hardcoded nil.
Backend contract (docs/plans/public-store-distance-consumer.md): distance
is a number, never null, 0 means unavailable. Implemented app-side ahead of
the backend - every change is forward-compatible, and the part that removes
the broken label works with no backend at all.
- PublicStoreListItem / PublicStoreDetail: + distance (optional, so today's
responses without the field still decode).
- StoreSummary.init(publicItem:): normalize the 0 sentinel to nil, so one
representation of 'unknown' reaches the label and the max-distance filter.
- fetchStoreDetail: send state/city from GuestLocationStore by default -
the server needs them to resolve the city centroid.
- formatDistance: empty string for nil/0/negative. It previously returned
'Distância indisponível' for nil, and - found by the new test - '0 m' for
0 and '-1000 m' for a negative.
- StoreCard: drop the distance segment and its '·' separator together,
otherwise the row ended in a dangling separator.
- StoreDetailView: drop the DISTÂNCIA tile and its divider instead of '--'.
Also fixes the same label in the authenticated flow when the user declined
location and has no address coordinates.
Tests: PublicStoreDistanceTests (decode with/without the field, passthrough,
0 normalization) + the empty case in HomeViewFilteringTests.
- RegistrationView / LoginEmailView / OtpView: pushed with no nav bar, so
they showed the oversized iOS 26 system glass back button. Wrapped each
in LCENavigationView with the standard AppBackButtonIcon, matching
LoginView and every other screen. Dropped the now-dead colorScheme dark
branches and forced .preferredColorScheme(.light) (app has no dark
theme).
- ContentView: root .auth <-> .main switched with no transition. Added
.move transitions on both branches and wrapped enterAuthFlow() /
LoginView's back action in withAnimation, so opening auth from Profile's
'Entrar ou Cadastrar' now slides in and back slides out.
- ProfileLoggedOutFlowTests: new test asserting the pushed auth screens
carry the LCENavigationView back button.
I reverted project.pbxproj earlier to drop Xcode's objectVersion churn
and wiped the manual signing config with it. Restored.
- project.pbxproj: back to the LC Prov profile set (Dev/Dist for the app,
Dev/Dist Push for NotificationService), CODE_SIGN_STYLE = Manual on all
targets - byte-identical to fix/signing/notification-extension-distribution.
- project.yml: was still pointing at the old 'PediFoods Dev/Dist Prov
Prof' names and CODE_SIGN_STYLE Automatic for the extension. Synced to
the same LC Prov set so 'xcodegen generate' reproduces the signing
instead of reverting it. Verified: regenerating from this project.yml
yields the same CODE_SIGN_* / PROVISIONING_PROFILE_SPECIFIER settings.
App Review rejected the 2026-08 build: tapping checkout as a guest
switched root to .auth, which replaced the whole UI with LoginView as the
NavigationStack root - no nav bar, no back, no dismiss. User was trapped.
- LoginView: rebuilt as a static screen in LCENavigationView with a back
button that sets root = .main, a 'Criar conta' and an 'Entrar' button,
and 'Termos de Uso' / 'Politica de Privacidade' links. Added #Preview.
- Forced .preferredColorScheme(.light) and fixed DS colors (the app has
no dark theme, so system dark mode was inverting the nav bar / title).
- Removed the entry-reveal animation machinery (heroVisible/textVisible/
buttonVisible/token/prepare flags across LoginView, AuthFlowView,
ContentView) - dead since guest browsing shipped and the root cause of
the 2026-08-06 'content stuck hidden' bug.
- enterAuthFlow() is now just root = .auth.
- UITestSupport.ensureLoggedIn taps 'Entrar' (new label).
- ProfileLoggedOutFlowTests: new test covering the choices and the way
back out of .auth.
- Localizable.xcstrings: catalog caught up to the new/removed strings.
Previous fix's VStack-level .frame(maxWidth: .infinity, alignment:
.leading) fixed the width but over-applied .leading to the empty
text too. Give it its own centered frame instead, matching the
isLoading/errorMessage branches right above it.
The empty-orders branch ("Nenhum pedido encontrado.") had no
.frame(maxWidth: .infinity), unlike the loading/error branches -
ScrollView sizes to its content's intrinsic width, so the whole
container (and its background) shrank to the text's width, leaving
the real black window visible on both sides. Forces the VStack (and
ScrollView) to always fill width regardless of which branch renders.
Cascades .buttonStyle(.plain) down from each LCENavigationView
instance instead of waiting on the LCEssentials package fix
(committed separately, unpublished: LC_Essentials commit 8b0f650) to
be released and this repo's Package.resolved bumped. Overrides
iOS 26's automatic Liquid Glass chrome on LCENavigationView's
internal nav buttons - including the invisible backfilled mirror
button on whichever side has no real action - without affecting any
button that already sets its own explicit style closer to itself.
setNavigationBarBackgroundColor was never called on the 15 screens
adopted in 3456184, so it stayed at the default .clear and the real
window background (black) showed through. Set it to
AppColors.backgroundLight on all of them, matching each screen's own
actual content background. Also wraps CartView's title in
LCENavigationView for consistency with the rest of the app - no
setLeftButton since Cart is a tab root, no back button needed.
The other reported bug (empty right-button slot rendering a visible
glass circle) is fixed in LCEssentials itself (separate repo,
commit 8b0f650 on fix/navigation/liquid-glass-button-chrome) but
won't take visual effect here until that's published and this
repo's Package.resolved is bumped to point at it.
Standardizes the back button to a single shared component
(AppBackButtonIcon, 32x32/14pt) instead of ~16 hand-duplicated
52x52/24pt copies, and wires each screen through LCENavigationView
per this project's mandatory-usage rule. Home and Store Detail
intentionally excluded - both have bespoke header designs (collapsing
header, hero-image overlay) this change would visually disrupt.
contentTopSpacing (18pt) was stacked on top of the content VStack's
own 24pt inter-section spacing, giving header-to-Categorias a wider
gap (42pt) than every other section-to-section gap in Home (24pt).
Dropping it to 0 makes the gap consistent with the rest of the
screen.
ProfileLoggedOutView conflict: kept this branch's simpler
enterAuth()-closure version over main's inline-embedded LoginView
(fix/profile/logged-out-auth-intro, predates the login-entry-
animation-bug fix). That bug was the actual reason the separate-
screen approach looked broken; it's already fixed here
(decisions/2026-08-06-login-entry-animation-bug.md), so the simpler
pattern works without re-threading a root binding through
MainTabView/ProfileLoggedOutView, which this branch deliberately
removed in favor of the closure. Ported the location-usage-
description Portuguese copy and the entitlements additions
(aps-environment, location.push) from main.
Union of both branches' entitlements (aps-environment + location.push
from this branch, App Attest CDhash opt-in from PR #41). Signing
settings resolved to Manual/Apple Distribution/AppStore profile -
this branch independently introduced the same Automatic/Apple
Development regression as PR #41 (see e93ccd2); one line
(PROVISIONING_PROFILE_SPECIFIER) merged silently to the broken value
without a marked conflict, caught by manual review and corrected
alongside the marked conflicts.
PR #41's App Attest environment fix (0bfdbb5) changed the Release
config's code signing from Manual/Apple Distribution/AppStore
provisioning profile to Automatic/Apple Development/no profile -
described in its own commit message as switching "local signing to
automatic" for App Attest testing, but applied to the same
config CI archives from for App Store submission. Automatic signing
needs an interactive Apple ID session (headless CI can't do that -
see docs/ci-cd/macos-runner-appstore-delivery.md section 2), and an
Apple Development identity can't produce an App-Store-uploadable
archive. Restores the prior signing settings, keeps the App Attest
environment fix itself untouched.
Resolves the App Attest env/entitlements changes onto the flattened
PediFoods.xcodeproj structure (Darwin/PediFoods.xcodeproj no longer
exists on this branch). Also restores Release signing to Manual /
Apple Distribution / AppStore provisioning profile - the merged-in
fix had switched it to Automatic / Apple Development, which breaks
headless CI archiving.
FiltersModalView.swift was 0% covered. Reaching it via guest mode hit
the backend's App Attest simulator-bypass rejection (403
APP_ATTEST_VERIFICATION_FAILED on /api/public/session, confirmed via
curl - a pre-existing, out-of-repo backend issue already documented in
decisions/2026-08-06-ui-test-account-and-app-attest-bypass.md), which
kept the guest address picker stuck showing a load-error sub-screen.
While chasing that, found a real bug in ContentView.swift:
.sheet(item: $appState.activeModal) had no onDismiss, so an
interactive swipe-to-dismiss never reset the bound item to nil -
anyone who swipes the address picker away without picking a location
leaves appState.activeModal stuck non-nil, silently breaking the next
modal presentation app-wide. Fixed with
onDismiss: { appState.activeModal = nil }.
Rewrote HomeFiltersFlowTests to use the authenticated QA account
instead of guest mode, routing around the backend-blocked guest wall
entirely. Also fixed a separate, real XCUITest issue: a plain .tap()
on the filter icon (inside Home's .offset()-transformed collapsing
header) reliably produced "Computed hit point {-1, -1}" - fixed via
coordinate(withNormalizedOffset:).tap().
Verified: HomeFiltersFlowTests passed clean across 2 consecutive
isolated runs. Full-suite regression run could not be completed this
round - the local environment stopped completing any instrumented
test launch afterward (reproduced across background/foreground,
clean DerivedData, simulator reboot, decoupled build/test, process
cleanup), unrelated to these changes. Documented in
decisions/2026-08-11-coverage-push-to-85-percent-status.md, with a
next-session TODO to run the full suite once the environment recovers.
testConfirmarEPagarWithCreditCardOpensCardSelectionWithoutSubmitting now
also taps CardSelectionSheet's "Adicionar novo cartão", which opens
PaymentCardView (CheckoutView.swift's own card-entry form - a distinct
struct from AddCardFormView.swift, which is a separate screen reached
from Profile -> Meus Cartões and already covered). Doesn't fill or
submit anything, just reaches the form and dismisses back through both
sheets.
Extracted the shared "x" close-button dismiss logic (used by both
CardSelectionSheet and PaymentCardView) into a private
dismissViaCloseButton helper.
Verified stable across 2 consecutive class-level runs.
Adds testConfirmarEPagarWithCreditCardOpensCardSelectionWithoutSubmitting:
selecting Cartão de Crédito and tapping "Confirmar e Pagar" opens
CardSelectionSheet (a separate struct in CheckoutView.swift) rather than
submitting an order - confirmed by reading
CheckoutView+Logic.handleConfirmPaymentTap(), which returns early before
any order-creation code when useInAppPayment && paymentMethod ==
.creditCard. Dismissed via the sheet's own close button, never selects a
card or submits anything, consistent with the earlier explicit user
direction not to create real order data during this coverage push.
Real bug found and fixed: reachCheckoutWithOneItem's product "+" button
selector (app.buttons.matching(identifier: "plus")) is the same class
of bug already fixed for the tab bar's cart icon - once a product's
quantity is > 0, its outer Button's identifier moves off itself onto a
nested Image (the row's own quantity Text takes over the Button's
accessible identity). This broke today specifically because the
standing QA account's cart has genuinely accumulated real quantities
across many runs, eventually leaving no untouched (quantity == 0)
product for the old selector to find - confirmed via screenshot showing
the "+" controls clearly rendered on screen while the buttons-only
query found nothing. Fixed by targeting the nested Image's identifier
directly (app.images.matching(identifier: "plus")), same fix pattern as
the cart-tab icon. This is shared by all three tests in the file via
reachCheckoutWithOneItem.
Also bumped two real-network timeouts based on trace evidence (not
guesses): store-detail load 15s -> 25s, OTP-request-to-Verificação-screen
15s -> 25s in UITestSupport.ensureLoggedIn.
Verified: the new test passes consistently in isolation and alongside
the other two tests in the class. One remaining flake
(testAddProductToCartAndReachCheckout hitting "Login never completed"
when run back-to-back with two other real-login tests in the same
invocation) confirmed via isolated rerun to be real backend load from
three consecutive real login/logout cycles, not a code regression -
passes cleanly alone.
Adds testCheckoutPaymentMethodSelectionAndAddressAlterar, exercising
CheckoutView's payment-method row selection and the address picker's
"Alterar" entry point without ever tapping "Confirmar e Pagar" -
deliberately not submitting a real order (explicit user direction:
cover the screen, don't create real order data in the QA account).
Extracted the shared reach-checkout steps from
testAddProductToCartAndReachCheckout into a private helper,
reachCheckoutWithOneItem, reused by both tests.
Fixed the same "not hittable" Back-button bug (already documented in
UITestSupport.swift) inline here too - tapping a Back button that
exists but is mid pop-transition throws a fatal, uncatchable failure;
needs an .isHittable check with a short poll, not just .exists.
Verified stable across 2 consecutive class-level runs.
Replace order_status-only NotificationCenter path with a single
DeepLinkDestination enum + PushDeepLinkParser, decoded once in
PushNotificationCoordinator and dispatched via ContentView.route(to:).
Also fixes NotificationService reading userInfo["image"] instead of
the guide's stale "imageUrl" key.
Build the full client half of docs/api/push-notifications-integration-guide.md:
OS permission + APNs device-token registration and pipeline wiring, profile
notifications/biometric-login toggles on the Ver Perfil screen reflecting
server truth, order-tracking opt-in fallback prompt, profile-cache refresh
on every mutation, a Notification Service Extension for rich/image push,
the Push Notifications capability, targeting-attributes sync, campaign open
tracking, and tap-to-order deep linking with foreground notification display.
Root cause of the permanent stuck-at-challenge symptom: a stale
appAttestKeyId in Keychain (Secure Enclave key invalidated by an app
reinstall or signing change) makes generateAssertion fail every time
with DCError code 2 (invalidInput). Only NetworkError 403 was clearing
the stored key, so this local rejection was never recovered from -
every guest-authed call kept retrying the same broken key forever.
Catch DCError here too and fall through to fresh attestation.
Guest session handshake fails silently after the challenge step - no
console output, just a generic "could not load" message in the UI.
DCAppAttestService errors (generateKey/attestKey/generateAssertion)
propagate up uncaught by anything that logs them. Add explicit logging
at each step so the real thrown error is visible instead of debugging
blind.
com.apple.developer.devicecheck.appattest-environment was hardcoded to
"development" for every build, including the App Store/TestFlight
distribution build. Apple's App Attest servers validate this claim
against how the app was actually signed/distributed, so a "development"
claim on a real distribution build fails - guest session handshake
never gets past the challenge step, no store/city data ever loads.
Parameterized per configuration: development for Debug, production for
Release, via an APP_ATTEST_ENVIRONMENT build setting.
App Store Connect flagged a validation warning: code references a
location API (guest store locator) but Info.plist has no
NSLocationWhenInUseUsageDescription, which would cause an App Review
rejection if left unaddressed. Added via INFOPLIST_KEY_* build setting
since this target generates its Info.plist from build settings rather
than a static file.
Binary upload itself succeeded - the only failure was
upload_to_app_store's default auto-submission colliding with an
existing in-progress review submission. CI should deliver the build;
submitting for review stays a deliberate manual step in App Store
Connect.