Skip to content

Release v1.4.0 (native — runtimeVersion 1.2.0 → 1.3.0) - #109

Merged
Muawiya-contact merged 61 commits into
mainfrom
develop
Sep 5, 2026
Merged

Release v1.4.0 (native — runtimeVersion 1.2.0 → 1.3.0)#109
Muawiya-contact merged 61 commits into
mainfrom
develop

Conversation

@Muawiya-contact

Copy link
Copy Markdown
Member

Release v1.4.0 — promotes develop to main.

⚠️ Native release — new APK

runtimeVersion 1.2.0 → 1.3.0 (new native modules: expo-splash-screen, expo-constants). Installed apps need a new APK — it's built and published automatically on merge (see below). version 1.3.0 → 1.4.0.

New features

  • Public like counts — every card shows how many people liked it (others' + your own, hidden at 0), instant on tap.
  • "What's New" card — one-time, dismissible, features-only; shows on first launch of this build.

Fixes & improvements

  • Instant launch (splash held until first frame, no blank flash).
  • Saved concepts now appear on Profile; History updates live after completing; no false "Offline" banner flash; Stats count the real catalog; snappier optimistic taps.
  • Backend: stranded-generation reaper + slug-collision fix, no pooled connections held across Gemini calls, batched reminder claims, models/README synced, openapi closed in prod, generation moved off the request path (low-watermark prefetch).
  • Removed the redundant "Alerts" card from Personalization.

Infra

  • CI security/quality audit + Dependabot (patch-only for SDK packages).
  • Release-only APK pipeline: a production-channel APK at a stable link, rebuilt only on native releases.

What happens on merge

  1. release.yml → publishes production + preview OTA (runtime 1.3.0) and cuts the v1.4.0 tag + GitHub Release.
  2. release-apk.yml (native, runtimeVersion changed) → builds the production APK and publishes it to the stable apk-latest link (~15–20 min).

After merge — do

  • Wait for the Release APK run to finish, then install from the README link (…/releases/download/apk-latest/one-concept.apk). That production build then updates only on future releases.

Muawiya-contact and others added 30 commits September 5, 2026 00:35
Served its purpose diagnosing the v1.3.0 build; not a permanent workflow.
Expo SDK dictates the versions of expo/expo-*/react-native/react and
async-storage; a minor or major bump belongs to a deliberate SDK upgrade, not a
weekly Dependabot PR. Ignoring minor+major for that set stops a repeat of the
v1.3.0 bundling break while still letting patch security fixes through.
The production build errored in the JS bundling phase: Dependabot had merged
SDK-incompatible bumps (react-native 0.87.1, async-storage 3.x, react 19.2.8,
drifted expo-* patches). 'expo install --fix' pins every SDK-managed package
back to what Expo SDK 57 expects (async-storage 2.2.0, react-native 0.86.3,
react 19.2.3, expo-* aligned). npm ci and tsc both pass.

(cherry picked from commit 9f691fc)
Bumps [@react-navigation/bottom-tabs](https://github.com/react-navigation/react-navigation/tree/HEAD/packages/bottom-tabs) from 7.18.17 to 7.18.18.
- [Release notes](https://github.com/react-navigation/react-navigation/releases)
- [Changelog](https://github.com/react-navigation/react-navigation/blob/@react-navigation/bottom-tabs@7.18.18/packages/bottom-tabs/CHANGELOG.md)
- [Commits](https://github.com/react-navigation/react-navigation/commits/@react-navigation/bottom-tabs@7.18.18/packages/bottom-tabs)

---
updated-dependencies:
- dependency-name: "@react-navigation/bottom-tabs"
  dependency-version: 7.18.18
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Bumps [react-dom](https://github.com/react/react/tree/HEAD/packages/react-dom) from 19.2.3 to 19.2.8.
- [Release notes](https://github.com/react/react/releases)
- [Changelog](https://github.com/react/react/blob/main/CHANGELOG.md)
- [Commits](https://github.com/react/react/commits/v19.2.8/packages/react-dom)

---
updated-dependencies:
- dependency-name: react-dom
  dependency-version: 19.2.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
The first entry is the current version and the source of truth the card compares
against; bump it in lockstep with expo.version each release.
Device-global (not per-account) since the card is about the app version. Reads
and writes are best-effort so a storage failure never crashes the app.
Shows the card whenever the last dismissed version isn't the current one, and
persists the current version on dismiss so it never reappears for that version.
A one-time card with a light fade + slide-up (built-in Animated, no new deps),
dismissible via the button, the close icon, tapping outside, or Android back.
Mount the card as an overlay in the signed-in app; it appears once per version
and never again once dismissed.
Read the current version from expo-constants (app.config.js expo.version) rather
than duplicating it in whatsNew.ts, so the two can never drift and a version-bump
that forgets the highlights just shows no card instead of silently no-opping.
Look the entry up by version with find(), which is safe if WHATS_NEW is empty —
no more WHATS_NEW[0] crashing at import.
The Modal's animationType="fade" already animates opacity; animating it again
on the card double-drove it. Keep only the slide-up.
Add a one-time "What's New" card on version change
…le/react-dom-19.2.8

Bump react-dom from 19.2.3 to 19.2.8 in /mobile
…le/react-navigation/bottom-tabs-7.18.18

Bump @react-navigation/bottom-tabs from 7.18.17 to 7.18.18 in /mobile
The saved list only had bare slugs, so the app could not name a saved concept
without the bundled demo catalog. Add a 'saved' field carrying {slug,title,topic}
alongside the existing 'bookmarks' slugs (kept for membership/count and for
already-installed apps that don't read the new field).
)

Parse the server's new 'saved' details into ProgressState.savedConcepts, and
reload full state after a save/unsave (the toggle endpoint returns no body) so
the saved list reflects the change. bookmarks slugs stay for the instant
optimistic card + count.
Signed-in bookmarks were resolved against the bundled 20-concept catalog, so
server-catalog saves never showed. Render from savedConcepts when present, fall
back to the bundled catalog for the signed-out demo. Broaden CategoryChip to
accept any label string (topic names match the Category values).
toggleBookmark reloads /me/state to refresh the saved list, but a failed reload
threw after the save had already persisted, so ProgressContext rolled the UI
back to un-saved. Catch the reload failure and patch in place instead, so a
succeeded toggle is never reverted; the saved list catches up on the next load.
Fix saved concepts not appearing on Profile (#90)
markLearned patched the cache with a client-side guess (the caller's concept id,
no title/topic) and only a full reload — an app restart — brought the true server
history. Reload /me/state after /daily/complete so the History tab reflects the
completed concept immediately. If the reload fails the completion has already
persisted, so patch in place rather than rolling it back.
markLearned recorded ProgressContext's locally-selected concept, so a signed-in
user completing the server's concept stored the wrong one — visible on the reload
failure fallback and as a brief wrong-title flash before the reload. Thread the
concept the screen actually showed (the server's, when signed in) into
markLearned, carrying its title and topic into the optimistic/fallback record.
Installing expo-splash-screen surfaced a latent conflict: react-dom had drifted
to 19.2.8 while react is pinned to SDK 57's 19.2.3, so a fresh resolve failed
(react-dom 19.2.8 needs react ^19.2.8). Pin react-dom back to 19.2.3 to match,
then add expo-splash-screen (SDK 57's ~57.0.8).
App() rendered null until the font loaded with no splash management, so every
launch flashed a blank screen. Keep the native splash up via preventAutoHideAsync
and hide it onLayout of the root view once the font is ready — the splash hands
straight over to real UI with no blank frame. Register the config plugin.
Three fixes to the splash wiring: (1) useFonts' error was ignored, so a font
failure left fontsLoaded false forever and the held native splash never hid —
the app was stuck on the splash. Treat fontsLoaded || fontError as ready so it
falls back to the system font instead of hanging. (2) Drop the dead
if(fontsLoaded) guard in onLayout (the view only mounts when ready). (3) Guard
hideAsync with a ref so repeated layout passes don't re-call it.
Hold the splash until first paint; no launch blank-flash (#93)
The 'Alerts — Daily reminders arrive in Phase 3' card was a non-interactive
placeholder; reminders are live and controlled by the Daily reminders toggle on
the Profile screen. Remove the card, its now-unused styles, and the now-unused
radius import.
Remove the redundant "Alerts" card from Personalization (#94)
apply() ran the optimistic update inside the serialised chain, so a tap's icon
only flipped after any prior mutation's network finished — Like felt laggy right
after Save/Mark-learned (now two round trips each). Apply the optimistic update
immediately, keep the network runs serialised, apply the whole-state server
snapshot only when nothing else is pending (no flicker), and undo just the
failed change functionally (a flip is its own inverse; mark-learned removes its
record). Restores instant feedback without reintroducing the #39 clobber.
Counting likes per concept needs an index keyed by concept_id (the existing one
is keyed by user_id). Partial on liked_at is not null so it only covers likes.
Return the count of likes by OTHER users on the day's concept; the client adds
the viewer's own like on top, so a like/unlike is an instant +/-1.
The like number is shown wherever a card appears (Today, History, Saved), so the
learned and saved rows now include the same others'-likes count.
Parse the server's others'-likes count into Concept.likeCount and into the
learned/saved records, so every surface can render it.
Add a small flame+number badge, and show it in the concept action bar next to
the like button: others' likes plus the viewer's own (optimistic), hidden at
zero. Tapping like ticks it +/-1 instantly.
The count appears wherever a card is shown, per the issue: each row adds the
viewer's own like to the server's others'-count and hides it at zero.
Match the codebase's memoisation pattern (cf. learnedIds in ProgressContext) so
the liked-set isn't rebuilt on every render.
Instant optimistic feedback for Like/Save/etc. (#95 part A)
Public like counts on every card (#95 part B)
Codify the content policy: the card shows only new user-facing features, never
bug fixes, leaks, perf/UI tweaks, or removals — those belong in the release
notes. Re-curate the entry accordingly: the one genuine new feature this cycle
is public like counts, so 1.4.0 leads with that (the old 1.3.0 entry mixed in
fixes and never actually displayed — the card shipped after 1.3.0's build).
The card's mechanics (heading, version, once-per-version, dismiss, animation)
already meet the issue from the original build.
…only

What's New card: new features only (#97)
production-apk extends production (channel production, environment production) but
builds a sideloadable APK instead of the Play Store .aab. A phone on this build
only updates on a release to main (production channel) — never from develop.
On release, rebuild the sideload APK only when the release is native
(runtimeVersion changed) and publish it to a fixed 'apk-latest' release asset;
JS-only releases reuse the existing APK and update over the air. The asset lives
at a stable URL, so the README link never needs editing and nothing has to push
to the protected main/develop branches.
Link to the apk-latest release asset (stable URL) and document that an installed
app changes only on a release to main.
…iew)

actions/checkout had no ref, so a manual run would build from the default branch
(develop) and could ship unreleased code as the production APK. Pin the ref to
the release tag on a release event, or main on a manual run.
…review)

The workflow triggers on release:published and itself publishes the apk-latest
release. GitHub's GITHUB_TOKEN non-recursion rule already prevents a loop, but
add a job-level guard (skip when the release is apk-latest) as insurance against
a future switch to a PAT.
Production APK on release only; stable install link
Native release: expo-splash-screen and expo-constants were added since the last
build (runtime 1.2.0), so installed apps need a new APK. Advance the native-ABI
runtime to 1.3.0 (decoupled from the marketing version, per app.config.js).
chore: bump to v1.4.0 (version 1.3.0→1.4.0, runtimeVersion 1.2.0→1.3.0)

@Muawiya-contact Muawiya-contact left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

ok

@Muawiya-contact
Muawiya-contact merged commit eea12ed into main Sep 5, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant