Conversation
Apple sign-in stored the live session, then tried to capture Apple's revocation token. On capture failure the catch called signOut() and rethrew, so the user saw "sign-in failed". signOut() is purely local (clears signInMessage and the session); it makes no server call. The server account and Apple grant stayed live, leaving an account the user believes was never created. The Apple authorization code is single-use and already consumed, so a retry cannot re-capture it, and the account could not later be fully deleted because deletion needs that token to revoke Apple's grant. The account and session are genuinely usable, and the server deletion flow already falls back to manual Apple revocation when the token is absent. Treat capture as best-effort: log a warning and keep the successful sign-in instead of tearing it down. Also fix ci(ios-release): the preflight "Run iOS tests" step unconditionally built -scheme Localhost. Rebuilding an accepted release checks out that tag, and tags ios-v0.1.0 through ios-v0.3.0 define no schemes block, so xcodegen generates no Localhost scheme and xcodebuild fails before archive/upload. Following the existing tag-compatibility pattern, derive behaviour from the checked-out sources and skip the preflight tests when the tag has no Localhost scheme; the Archive step still validates the rebuild.
Healthy health responses suppress completion logging, which previously bypassed outcome metadata extraction. Strip the metadata before deciding whether to log so routine health checks cannot expose internal observability details to clients.
Contributor
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 117 out of 118 changed files in this pull request and generated no new comments.
Suppressed comments (1)
ios/WingDex/Services/AuthenticatedRequest.swift:38
- This accepts the all-zero trace ID even though that value is invalid under W3C Trace Context and the web validator already rejects it in
src/lib/api-error.ts:1. A malformedX-Trace-Idcan therefore be logged and shown as a native correlation reference that cannot identify a real trace. Reject the all-zero value here as well.
Contributor
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 117 out of 118 changed files in this pull request and generated no new comments.
Suppressed comments (6)
functions/lib/log.ts:240
failWithHeadersalso silently discards itspropertiesargument, so callers cannot attach diagnostic metadata to the terminal request event despite the public responder contract accepting it. Preserve approved properties through middleware, or remove the parameter and update callers to emit an explicit safe event.
ios/WingDex/Views/HomeView.swift:34AvatarViewis hidden from the accessibility tree, so the label attached to that child is ignored and this settings button has no VoiceOver name. PutaccessibilityLabel("Settings")on theButtonitself.
ios/WingDex/Views/WingDexView.swift:144AvatarViewis hidden from the accessibility tree, so the label attached to that child is ignored and this settings button has no VoiceOver name. PutaccessibilityLabel("Settings")on theButtonitself.
ios/WingDex/Views/OutingsView.swift:105AvatarViewis hidden from the accessibility tree, so the label attached to that child is ignored and this settings button has no VoiceOver name. PutaccessibilityLabel("Settings")on theButtonitself.
src/lib/model-cache.ts:50- Capping a server-provided
Retry-Afterat five seconds retries before the server's requested time. A 429 withRetry-After: 60, for example, is retried twice while still throttled, wasting bandwidth and making the model download fail instead of recovering. Honor valid header values; keep the cap only for locally generated exponential backoff.
functions/lib/log.ts:236 - The responder still accepts failure
properties, but now discards them unconditionally. Existing callers such asdata/observations.tspass safe counts and IDs for diagnosing validation failures, so those fields silently disappear from the only terminal request event. Either transport approved properties to middleware or remove this parameter and migrate callers to an explicit safe event so the API cannot imply metadata was recorded.
This issue also appears on line 239 of the same file.
… photos Wikimedia's User-Agent policy asks for a client name and a contact route and blocks non-descriptive agents. SpeciesDetailView sent no agent at all, and the other callers each invented their own string. A website satisfies the contact requirement, so no address is exposed and no secret is needed. Reference photos now name their creator and license. A sample of 144 Commons bird photos found 139 requiring attribution, across eight different licenses, so the blanket CC BY-SA 4.0 notice was wrong for most of them and filtering to attribution-free images would have emptied half the galleries. Artist and LicenseShortName already arrived in the extmetadata both clients request and were being dropped at parse time. The caption links to the file page, which carries the full notice.
The species view claimed every image was CC BY-SA 4.0. A sample of 144 Commons bird photos found eight different licenses, so the notice was wrong for most of them, and it named no creator even though 139 of the 144 require one. The file page URL is derivable from the image URL, since the file name is the path segment before the rendered width, so the credit needs one request per species and nothing new in taxonomy.json. That matters because the occurrence prior is keyed by sha256(taxonomy.json) and any new field there would invalidate the shipped blob. The reference caption keeps its plumage label and carries the credit on its own line, so neither has to be truncated to fit.
The plumage label and the photo credit were still sharing one line here, so the caption wrapped and neither read cleanly. Split them the same way the web does.
The HStack centred its columns, so the taller caption lifted the reference photo out of line with the user's. Align to the top instead, which holds regardless of how many lines the credit takes.
The model download failed on localhost but worked on Cloudflare. Hosts disagree about what a .gz asset means: Cloudflare serves it as an opaque body, so the raw gzip arrives and the loader decodes it, while wrangler dev labels it Content-Encoding: gzip off the extension, so the browser decodes it in transit and the loader was handed 24 MiB of already-decoded data to gunzip. Measured against the shipped meta.json: the same request returns gzip_bytes 16478112 from Cloudflare and raw_bytes 24123497 from wrangler dev. The gzip magic distinguishes the two and cannot collide, since a decoded blob starts with WDOP. Dropping the Blob round trip also avoids copying 16 MiB and lets the decode be tested at all: jsdom's Blob has no stream(). Every existing model-cache test stubs global fetch, so none of them could see a transport difference. The download failure was also swallowed into component state without a log, which is why this surfaced only by being noticed.
Contributor
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 126 out of 127 changed files in this pull request and generated no new comments.
Suppressed comments (7)
ios/WingDex/Views/SpeciesDetailView.swift:267
- The credit tuple is assigned even when Commons returns neither
ArtistnorLicenseShortName, which leaves an effectively emptyPhotolink. Keep the file-page attribution visible with a fallback label, as the web species detail does.
ios/WingDex/Views/SpeciesDetailView.swift:172 - Species without a dex thumbnail use the asynchronously fetched Wikipedia image (
displayedFullImageUrlfalls back tofullImageUrl), but this task runs only once andfetchImageCreditreads onlyentry?.thumbnailUrl. Those displayed hero images therefore never receive a photo credit. Key the task to the displayed image URL and derive the file page from that URL.
This issue also appears on line 267 of the same file.
functions/lib/geocoding.ts:104
- The substring check drops legitimate region context when a place name merely contains the state or country name. For example,
California Cityin California is treated as already containing the state, so same-named results lose the context this function is meant to provide. Compare complete comma-separated label parts instead.
src/components/flows/AddPhotosFlow.tsx:1041 artistis optional inGalleryImage, so using it as the render guard hides the file-page source and any available license whenever Commons omits that field. Guard ondescriptionUrland use a source fallback so every displayed gallery image remains attributable.
src/lib/bird-id-local.ts:244- Discarding both writer promises creates unhandled promise rejections when a gzip stream is corrupt or truncated, in addition to the error returned by reading
ds.readable. Await the producer and consumer together so decompression failures stay within the caller's normal error path.
ios/WingDex/Services/AuthenticatedRequest.swift:37 - This accepts the all-zero trace ID, although W3C reserves it as invalid and the web validator rejects it. A malformed header can therefore produce a bogus
[ref: 00000000]in native logs. Reject the zero value before normalizing it.
src/tests/add-photos-flow.test.ts:65 - This decorative separator uses non-ASCII box-drawing characters in a code comment. Keep code comments to ASCII punctuation.
This was
linked to
issues
Aug 10, 2026
jlian
added a commit
that referenced
this pull request
Aug 10, 2026
… stale The iOS release failed on 2026-08-10 with "Could not determine the next iOS release version", because semantic-release reported "The local branch main is behind the remote one". Mechanism: iOS Release and Release share the release-<ref> concurrency group, so they serialize. On the merge of #302 both triggered on fae9515 one second apart. Release ran first, published 1.24.0, and pushed the version-bump commit 44a508c to main. iOS Release then started 21 seconds later with a checkout pinned to fae9515, which by then was one commit behind the remote, and semantic-release refuses to release from a stale branch. The concurrency group is doing its job; the checkout was not. Resolving the ref at execution time picks up the bump the previous workflow just pushed. This was fixed once in 8a72195, then reverted in two steps: 60189c3 replaced the preflight ref with a resolver whose fallback was GITHUB_SHA, and b8f9dd9 pinned the publish job to github.sha to avoid archiving code other than the triggering commit. That concern does not apply under the shared concurrency group, where the commit landing mid-run is the version bump this release requires. Both jobs now select the ref inline, so the two modes are visible at the call site rather than hidden in a resolver step: a dispatch with release_version still checks out that tag to rebuild a shipped release, and everything else takes the branch tip.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.