Skip to content

feat(mobile): harden bootstrap, routing, and release gates (w6b) - #5421

Open
iscekic wants to merge 12 commits into
mainfrom
audit-w6b-bootstrap-release-ff5f
Open

feat(mobile): harden bootstrap, routing, and release gates (w6b)#5421
iscekic wants to merge 12 commits into
mainfrom
audit-w6b-bootstrap-release-ff5f

Conversation

@iscekic

@iscekic iscekic commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Summary

The Home screen now shows an Explore area with three shortcuts: Code Reviewer, Security Agent, and PR Review. The area stays visible when the session list is loading, empty, filled, or failed to load.

The Profile screen now paints first and loads account and organization details only after the screen transition settles, showing placeholders while it waits.

Opening a link with a broken review, session, or organization identifier now shows a not-found screen with a back action instead of a blank or broken screen.


The production host allowlist is now complete. It holds all seven production hosts from the committed environment file, including the three kiloapps.io endpoints, and a unit test reads that file and asserts every URL value passes the scheme and host checks, so a missing host fails before any build. A production build still fails on a missing required value, a wrong scheme, an off-allowlist host, or a missing Sentry source-map token.

Files
  • apps/mobile/src/lib/url-contract.js — new; holds URL_SCHEMES, PRODUCTION_HOSTS, assertUrlScheme, and assertProductionHost; the allowlist now lists all seven production hosts.
  • apps/mobile/app.config.ts — applies the scheme and host checks; makes missing env fatal in production; adds the Sentry token gate; bakes extra.isProductionBuild.
  • apps/mobile/src/lib/config.ts — applies the scheme check at runtime and the production host check when extra.isProductionBuild is true.

The root layout now derives its bootstrap routing and its render gating from one pure resolver instead of two hand-kept copies, so the routing effect and the visibility flags can no longer disagree. The resolver returns a closed union of routing tags plus the error, redirect, and hidden flags, and the routing effect switches over the tag. The old inline if-chain and the old inline gating derivations are deleted; behavior stays the same.

Files
  • apps/mobile/src/lib/bootstrap-decision.ts — new; exports the input, decision, and tag types and the pure resolver.
  • apps/mobile/src/app/_layout.tsx — calls the resolver in the routing effect and the render gate; replaces the inline if-chain with a switch.

The release workflow pins EAS CLI to 21.8.0 and splits the old build-and-submit step into a preflight job, a build job, an artifact download, an inspection step, and separate iOS and Android submissions. The preflight fails closed when the EAS production environment misses a required value or the config contract fails. The build no longer uses --auto-submit; submission runs from downloaded artifacts after inspection.

Files
  • .github/workflows/kilo-app-release.yml — pins the CLI, adds the preflight job, splits build and submit, adds download and inspection steps.
  • apps/mobile/eas.json — pins cli.version to 21.8.0.
  • apps/mobile/package.json — pins every eas-cli script to 21.8.0 and adds the assert:config script.

A new preflight script runs the fully evaluated Expo config and fails when the bundle id, package, scheme, associated domain, blocked permissions, Sentry plugin, or any required extra value violates the contract. The preflight invokes it inside the EAS production environment, so config drift fails before any build.

Files
  • apps/mobile/scripts/assert-expo-config.mjs — new; runs expo config --json and checks the contract values.

A new inspection script validates the EAS build result and the signed IPA and AAB before submission, and submission stops when an artifact violates a bundle, permission, endpoint, or debug-symbol contract. The IPA is checked for its bundle id, privacy manifest, usage descriptions, and SKAdNetwork endpoints; the AAB is checked for its package, blocked permissions, cleartext traffic, intent-filter host, and debug symbols.

Files
  • scripts/inspect-mobile-artifacts.mjs — new; validates build.json, inspects the IPA and AAB, and checks debug symbols.

The home screen gains an Explore section with Code Reviewer, Security Agent, and PR Review rows, and the PR Review row stays behind the existing PR Review feature flag. The section renders in the empty, populated, and error states of the session list, so the shortcuts remain available when sessions fail to load.

Files
  • apps/mobile/src/components/home/product-choices.tsx — new; three rows, PR Review gated by the flag.
  • apps/mobile/src/components/home/home-screen.tsx — renders ProductChoices after the sessions/promo branch.

The profile screen defers its two mount-time queries until the navigation transition settles, using a new useAfterInteractions hook, so the screen paints before the account and organization fetches start. The skeleton, stale, and error states stay, and the linked-accounts section now shows its skeleton while the interactions are pending.

Files
  • apps/mobile/src/lib/hooks/use-after-interactions.ts — new; returns false on mount, then true after InteractionManager.runAfterInteractions.
  • apps/mobile/src/components/profile-screen.tsx — gates both queries on the hook and keeps the skeleton and error states.

Six routes that read a required path parameter now parse it with parseParam and render InvalidRouteState with a bounded back target when the parameter is missing or malformed. Optional parameters keep their existing first-element unwrapping, and the session route no longer fires its query for a null session id.

Files
  • apps/mobile/src/app/(app)/(tabs)/(3_profile)/code-reviewer/[scope]/index.tsx — parses scope; renders InvalidRouteState.
  • apps/mobile/src/app/(app)/(tabs)/(3_profile)/code-reviewer/[scope]/manual-review.tsx — parses scope; renders InvalidRouteState.
  • apps/mobile/src/app/(app)/(tabs)/(3_profile)/code-reviewer/[scope]/reviews/[id].tsx — parses scope and id; back target depends on scope.
  • apps/mobile/src/app/(app)/(tabs)/(3_profile)/code-reviewer/[scope]/reviews/index.tsx — parses scope; renders InvalidRouteState.
  • apps/mobile/src/app/(app)/(tabs)/(3_profile)/organization/member-limit.tsx — parses memberId; renders InvalidRouteState.
  • apps/mobile/src/app/(app)/agent-chat/[session-id].tsx — parses session-id; disables the query and renders InvalidRouteState when null.

Tests: 13 test files added or updated.
Generated: none.


Verification

Two cases ran on iOS across two verification rounds.

Case What it proves Platform Result
EV-03 cold start to interactive Home A relaunch from force-quit lands on the interactive Home; no local sink observes the startup event in dev builds. iOS passed
EV-08 invalid route boundary A malformed deep link renders a bounded not-found state on the device; the route tests prove the InvalidRouteState back target. iOS passed

No round reproduced a defect on the unfixed build.
Recording: ev03-coldstart.mp4 shows the EV-03 cold launch from force-quit to interactive Home.

Visual Changes

Home screen. The user now sees an Explore section on Home with rows for Code Reviewer, Security Agent, and PR Review. In the picture, the EXPLORE header and the three rows sit below the Kilo Agents card and above the tab bar.

01-open-app.png

Invalid-route screen. The user now gets a bounded not-found state with a back action when a route param is malformed. No picture shows this change. The single candidate shows the session not-found state after a malformed deep link; no deep link yields a malformed param on the device, so the picture fails to show the new InvalidRouteState with Page not found and Go back. The co-located route tests prove that state instead.

Reviewer Notes

Human steps:

  1. Confirm the EAS production environment URL values match the committed apps/mobile/.env hosts before the first real production build; the release preflight fails closed on any mismatch. (after merge)
  2. Store SENTRY_AUTH_TOKEN in the EAS production environment with non-secret visibility (plain or sensitive). (after merge)
  3. Set EXPO_PUBLIC_SENTRY_ENVIRONMENT=production in the EAS production environment; the release preflight asserts it. The EAS preview environment no longer needs EXPO_PUBLIC_SENTRY_ENVIRONMENT=preview to avoid a crash, because the runtime host check now keys off the baked build intent. (after merge)
  4. Watch the first real release run: the signed IPA may lack PrivacyInfo.xcprivacy or the AAB may lack debug-symbols metadata; the follow-up fix is named in the plan. (after merge)
  5. The signed IPA's binary Info.plist is parsed with python3 plistlib; the release runner must provide python3. (after merge)

Notes: E2E: the follow-up commit 13f4d4b adds three production hosts to the build-time allowlist and a unit test; the host check only runs in production builds, so it has no runtime behavior to verify. The existing iOS verification still holds.

Add an Explore section with Code Reviewer, Security Agent, and PR Review
rows so an empty or erroring Home still offers an outcome-led first
action. Scope resolves as organizationId or the personal security scope;
PR Review stays feature-flag gated.
The expo config contract assertion hardcoded the ten ENV_KEYS names, so a
new key would silently drop out of the preflight check. Import ENV_KEYS
from src/lib/env-keys.js and iterate its keys instead.
@iscekic iscekic self-assigned this Aug 21, 2026
@iscekic iscekic changed the title feat(mobile): harden bootstrap, routing, and release gates feat(mobile): harden bootstrap, routing, and release gates (w6b) Aug 21, 2026
Comment thread apps/mobile/src/lib/config.ts Outdated
@kilo-code-bot

kilo-code-bot Bot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Executive Summary

Incremental review of the production-host allowlist and committed-.env host-contract test found no remaining issues.

Files Reviewed (2 files)
  • apps/mobile/src/lib/url-contract.js
  • apps/mobile/src/lib/url-contract.test.ts
Previous Review Summaries (3 snapshots, latest commit d7e4503)

Current summary above is authoritative. Previous snapshots are kept for context only.

Previous review (commit d7e4503)

Status: No Issues Found | Recommendation: Merge

Files Reviewed (3 files)
  • apps/mobile/app.config.ts
  • apps/mobile/src/lib/config.ts
  • apps/mobile/src/lib/url-contract.test.ts

Previous review (commit 4276142)

Status: 1 Issue Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 0
Issue Details (click to expand)

WARNING

File Line Issue
apps/mobile/src/lib/config.ts 52 Runtime host allowlist uses Sentry environment, so preview release builds crash on launch
Files Reviewed (2 files)
  • apps/mobile/src/lib/bootstrap-decision.ts
  • apps/mobile/src/lib/bootstrap-decision.test.ts

Fix these issues in Kilo Cloud

Previous review (commit 04cadd4)

Status: 1 Issue Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 0
Issue Details (click to expand)

WARNING

File Line Issue
apps/mobile/src/lib/config.ts 52 Runtime host allowlist uses Sentry environment, so preview release builds crash on launch
Files Reviewed (33 files)
  • .github/workflows/kilo-app-release.yml
  • apps/mobile/app.config.ts
  • apps/mobile/eas.json
  • apps/mobile/package.json
  • apps/mobile/scripts/assert-expo-config.mjs
  • apps/mobile/src/app/(app)/(tabs)/(3_profile)/code-reviewer/[scope]/index.tsx
  • apps/mobile/src/app/(app)/(tabs)/(3_profile)/code-reviewer/[scope]/manual-review.tsx
  • apps/mobile/src/app/(app)/(tabs)/(3_profile)/code-reviewer/[scope]/reviews/[id].tsx
  • apps/mobile/src/app/(app)/(tabs)/(3_profile)/code-reviewer/[scope]/reviews/index.tsx
  • apps/mobile/src/app/(app)/(tabs)/(3_profile)/organization/member-limit.tsx
  • apps/mobile/src/app/(app)/agent-chat/[session-id].tsx
  • apps/mobile/src/app/_layout.tsx
  • apps/mobile/src/components/home/home-screen.tsx
  • apps/mobile/src/components/home/product-choices.tsx
  • apps/mobile/src/components/profile-screen.tsx
  • apps/mobile/src/lib/bootstrap-decision.ts
  • apps/mobile/src/lib/config.ts - 1 issue
  • apps/mobile/src/lib/hooks/use-after-interactions.ts
  • apps/mobile/src/lib/url-contract.js
  • scripts/inspect-mobile-artifacts.mjs
  • plus 13 test files

Fix these issues in Kilo Cloud


Reviewed by grok-4.6 · Input: 109.6K · Output: 6.9K · Cached: 216.1K

Review guidance: REVIEW.md from base branch main

The routing effect reads only decision.tag and the render gating reads only
the three error flags and hidden. The seven intermediate derivations were
exported but never consumed; keep them as local consts inside the helper.
The runtime production-host check keyed off the Sentry environment, so a
preview release build with an unset EXPO_PUBLIC_SENTRY_ENVIRONMENT failed
closed and crashed on launch. Bake EAS_BUILD_PROFILE === 'production' into
expo extra and gate the check on that flag.
@iscekic iscekic added the human-ready The PR is ready for human review. label Aug 21, 2026

@pandemicsyn pandemicsyn left a comment

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.

pre-approving but think robot's inline comment is right and deploys via this new workflow will probably fail.

Comment thread .github/workflows/kilo-app-release.yml
Comment thread apps/mobile/src/lib/url-contract.js
Add chat.kiloapps.io, events.kiloapps.io, and notifications.kiloapps.io to the production host allowlist, and add a host-contract test that asserts every committed .env URL value against the allowlist.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

human-ready The PR is ready for human review.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants