Skip to content

fix(android): attach GPS location on recordings - #12179

Merged
kodjima33 merged 5 commits into
mainfrom
fix/android-gps-location-nil
Aug 25, 2026
Merged

fix(android): attach GPS location on recordings#12179
kodjima33 merged 5 commits into
mainfrom
fix/android-gps-location-nil

Conversation

@undivisible

@undivisible undivisible commented Aug 25, 2026

Copy link
Copy Markdown
Collaborator

Report

Android conversation/recording JSON always had geolocation: null / location=nil. The reporter suspected a missing always-on / ACCESS_BACKGROUND_LOCATION grant. They also left the app in the foreground, turned on the recorder, and still got nil.

Root cause

Not missing always-on. The attach path already exists (ConversationLocationCapturePATCH /v1/users/geolocation → Redis snapshot on finalize) and is awaited on phone-mic and device record start.

What actually dropped Android coordinates:

  1. Never requested location at record start. Capture only checked permission. A skipped onboarding page or a first-run Android 12+ grant left the path on denied, so it uploaded nothing even with the activity visible.
  2. 1s high-accuracy GPS then last-known. Default Geolocator accuracy is Android PRIORITY_HIGH_ACCURACY. A cold GPS fix routinely exceeds 1s. getLastKnownPosition() is often null on Android until this app has received a fix, so both legs failed in the foreground.
  3. Non-timeout errors skipped last-known. A SecurityException / settings failure from high-accuracy GPS (common with approximate-only grants) never fell back.

Background/always-on is not required for a visible recorder. Android already declares FOREGROUND_SERVICE_LOCATION and only asks for while-in-use. ACCESS_BACKGROUND_LOCATION is still not requested (Play Store prominent-disclosure). iOS "Always" remains iOS-only for BGTask windows.

Fix

  • Request while-in-use at record start when permission is denied (not deniedForever).
  • Prefer last-known (including Android LocationManager fallback), then a medium-accuracy current fix with a 2s budget.
  • Treat any current-fix error as a miss, not only TimeoutException.
  • Use the same last-known + medium-accuracy path in the Android foreground-task isolate.
  • Document in the capture class and AndroidManifest that always-on / ACCESS_BACKGROUND_LOCATION is intentionally not used.

Test plan

  • flutter test test/unit/conversation_location_capture_test.dart (no device)
    • uploads a fresh position when last-known is empty
    • uploads last-known immediately (does not wait on a hanging current fix)
    • does not prompt or upload on deniedForever
    • requests while-in-use at record start when denied
    • uses last-known when a fresh fix would throw
    • uploads nothing when both last-known and current fail
  • Manual Android: grant while-in-use (not Always), keep the app visible, start the phone-mic recorder, finish a short conversation, confirm geolocation on the conversation JSON
  • Manual Android: approximate-only grant still attaches coordinates
  • Manual Android: deny location → record → system prompt → grant → location attached
  • Confirm Settings → Permissions still does not ask for Android Always / background location

Failure class (fixes)

Failure-Class: none

Review in cubic


Note

Medium Risk
Changes permission prompts and location acquisition at recording start and in the foreground location service; scope is limited to geolocation attach, not new background permissions.

Overview
Fixes null conversation geolocation on Android when recording in the foreground with only while-in-use location—not missing ACCESS_BACKGROUND_LOCATION.

ConversationLocationCapture now requests while-in-use permission at record start when status is denied (not deniedForever). Capture tries last-known first (with Android LocationManager fallback), then a medium-accuracy current fix with a 2s budget; any current-fix failure is handled without blocking recording. Docs in code and AndroidManifest state that background location is intentionally not requested.

The foreground-service location refresh uses the same last-known → medium-accuracy pattern, with errors reported to the main isolate.

Unit tests cover permission prompting, last-known-first behavior, and failure paths.

Reviewed by Cursor Bugbot for commit 138043e. Configure here.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Permission prompt exceeds capture timeout
    • Moved the while-in-use permission prompt outside the 3s totalTimeout so the system dialog can complete before GPS/upload starts, and added a regression test for a grant slower than that budget.

You can send follow-ups to the cloud agent here.

Reviewed by Cursor Bugbot for commit 138043e. Configure here.

// Prompt at record start so a skipped onboarding page still gets a fix
// when the activity is visible. deniedForever is not re-prompted.
permission = await _requestPermission();
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Permission prompt exceeds capture timeout

High Severity

_requestPermission now runs inside the existing 3s totalTimeout, and currentPositionTimeout grew to 2s without raising that budget. On the new denied path the system dialog almost always outlives 3s, so captureAndUpload returns early while the dialog is still up. Callers then proceed to mic permission / recording start, racing finalize and risking stacked permission requests.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 138043e. Configure here.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Fixed at 79edabb (HEAD d125f9e). _requestPermission runs outside totalTimeout; the 3s budget only wraps _captureAndUpload. Regression: does not time out while the user answers the location permission prompt.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 138043e6ac

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

} on TimeoutException {
// A recent OS fix is preferable to losing the conversation location when
// a fresh GPS fix is slow indoors.
position = await _getLastKnownPosition();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Refresh stale cached positions before uploading

When the OS has a non-null fix from before the user moved, this unconditional last-known-first path uploads that old coordinate as the recording's location and never invokes _getCurrentPosition; the foreground refresher added in this commit uses the same ordering, so the app can repeatedly attach a stale location. Check position.timestamp against a bounded freshness window and request a current fix when it is expired, with a regression test for an old cached position; the rewritten fresh-first test currently provides no such guard or external basis for accepting every cached fix.

AGENTS.md reference: AGENTS.md:L126-L126

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Implemented at d125f9e. lastKnownMaxAge is 5m with _isFresh. Stale last-known falls through to a current fix, then stale last-known if current fails. Tests: refreshes a stale last-known position before upload, uses a stale last-known when the current fix fails. Same window in foreground.dart.

if (permission == LocationPermission.denied) {
// Prompt at record start so a skipped onboarding page still gets a fix
// when the activity is visible. deniedForever is not re-prompted.
permission = await _requestPermission();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Wait for the permission decision before timing out

When a user takes more than the three-second totalTimeout to answer this newly added system prompt, Future.timeout returns false without cancelling _captureAndUpload; the recording callers then proceed while this operation can resume later and update Redis after capture has started or a short device conversation has already finalized. Keep the interactive permission request outside the bounded location-acquisition timeout, or fence the timed-out operation so it cannot complete late.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Implemented. Permission request is unbounded; totalTimeout applies only to GPS/upload. Late _captureAndUpload completion is fenced with timedOut / isCancelled so a timed-out run does not upload. Same test as the timeout-vs-prompt case.

if (permission == LocationPermission.denied) {
// Prompt at record start so a skipped onboarding page still gets a fix
// when the activity is visible. deniedForever is not re-prompted.
permission = await _requestPermission();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Start the foreground service after granting location

For the first-run/skipped-onboarding case targeted here, HomePage checks permission first and skips ForegroundUtil.startForegroundTask() while it is denied, then immediately calls streamDeviceRecording, which can grant permission on this line. Nothing retries foreground-service startup after that grant, so these users receive the one-off upload but no periodic location refresh until the page or app is recreated, leaving long-running/background device capture on the stale initial snapshot. Start the Android foreground task after a successful newly requested grant.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Implemented. ConversationLocationCapture(onNewlyGranted: _startAndroidLocationForegroundTask) in capture_controller.dart. Hook fires on a new while-in-use/always grant only; tests assert it does not fire on deniedForever or an already-granted check.

Comment on lines +106 to +108
} catch (e) {
Logger.log('Fresh conversation location fix failed: $e');
return false;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Instrument the new exhausted location fallback

When no cached position exists and the fresh fix throws or times out, this new catch converts the failure into a silent fail-open return and recording continues without geolocation; the local log does not expose how often the Android fix remains broken in production. Record this through the shared fallback telemetry surface with an exhausted outcome (and instrument the equivalent foreground-task branch) rather than relying only on Logger.log.

AGENTS.md reference: AGENTS.md:L95-L95

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Declining. docs/agents/fallback-telemetry.md is Python/Swift/Rust only — there is no Dart record_fallback surface. Adding a fake Dart telemetry path would not satisfy the contract. Exhausted GPS still fail-opens with a local log; recording continues.

@Git-on-my-level Git-on-my-level left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks @undivisible — solid root-cause analysis, and the permission posture here is exactly right (while-in-use only, no ACCESS_BACKGROUND_LOCATION, documented in the manifest).

The diagnosis holds up against the code, and the earlier "prompt inside the 3s timeout" concern is fixed at this head with a regression test. Two CI blockers are attributable to this PR's own changes, so requesting changes for those:

1. Dart Analyze & Tests — analyzer ratchet: unnecessary_null_comparison (2 new occurrences, baseline 0)

  • app/lib/services/capture/conversation_location_capture.dart:111if (position == null) return false; is unreachable: if the current fix fails, the catch at 106–109 already returns; otherwise position is non-null. Please remove.
  • app/lib/utils/audio/foreground.dart:44if (locationData == null) is likewise dead: both branches either assign or return in their catch blocks. Please remove.

flutter test never ran — the ratchet gate precedes it. These should just be deleted rather than baselined (they're new dead code, not pre-existing debt).

2. Hygienefailure-class-protocol: commit 440c2f8824 (fix(android): …) is missing its Failure-Class: FC-<slug> | new | none trailer. Your latest commit already carries Failure-Class: none; the first commit needs the same treatment — reword it (rebase) with either none or a real class from scripts/pr-preflight --suggest.

Two non-blocking observations, both verified in the code, worth addressing or consciously accepting:

  • Stale last-known uploads: conversation_location_capture.dart:98-110 will upload any non-null cached position without a freshness check, so a fix from before the user moved can become the recording's location. A bounded freshness window on position.timestamp (falling back to the current fix when stale) plus a regression test would make the attach trustworthy.
  • Foreground refresh gap: app/lib/pages/home/page.dart:483-489 starts the foreground location service only when permission was already granted at page load, so a fresh grant from the new record-start prompt leaves the periodic refresh unstarted until the page is recreated. A retry after a newly granted permission would close that.

On the Codex P1 suggestion to use record_fallback: not applicable here — the fallback-telemetry contract (docs/agents/fallback-telemetry.md) covers Python/Swift/Rust and there's no Dart surface for it today.

Left for human maintainer review: the new runtime while-in-use prompt at record start is a UX/product decision worth explicit sign-off.


by AI on behalf of David — if you need David’s attention urgently, please @Git-on-my-level and escalate with need human response.

@Git-on-my-level Git-on-my-level added needs-maintainer-review Needs a human maintainer to sign off before merge android labels Aug 25, 2026
@undivisible
undivisible force-pushed the fix/android-gps-location-nil branch from 0d33165 to d125f9e Compare August 25, 2026 09:15
@undivisible

Copy link
Copy Markdown
Collaborator Author

@Git-on-my-level both CI blockers are addressed at d125f9e: dead Position? null checks removed (late final Position in capture + FGS isolate); Failure-Class: none is on the fix commits and scripts/failure-class validate is clean against this PR body (test commits f7eafbd / d125f9e do not need trailers; no rebase).

Non-blocking: 5m last-known freshness + FGS start after a newly granted while-in-use are in at the same SHA.

Codex P1 (record_fallback) declined — no Dart fallback-telemetry surface; see docs/agents/fallback-telemetry.md.

Please re-review.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d125f9eceb

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +88 to +91
if (permission == LocationPermission.denied) {
// Prompt at record start so a skipped onboarding page still gets a fix
// when the activity is visible. deniedForever is not re-prompted.
permission = await _requestPermission();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Request location only when a recording is actually starting

When the home page opens with no connected device and location permission is denied, HomePage still unconditionally calls streamDeviceRecording(device: connectedDevice) (page.dart:498-502), and that method calls captureAndUpload() even when device is null (capture_controller.dart:1670-1681). This new request therefore shows the sensitive system location prompt on ordinary home-page entry on both Android and iOS, rather than at the claimed recording start; users can deny it without context and may later be unable to attach location when they do record. Gate permission prompting on an actual recording/device path, while allowing noninteractive callers to keep the former check-only behavior.

Useful? React with 👍 / 👎.

@Git-on-my-level

Copy link
Copy Markdown
Collaborator

Re-reviewed at d125f9e — thanks @undivisible, both blockers from my earlier review are resolved and verified at this head:

  • Dead null checks gone: conversation_location_capture.dart now uses late final Position with catch-based fallback, and the FGS isolate in foreground.dart does the same — Dart Analyze & Tests is green here, so the unnecessary_null_comparison ratchet is clear.
  • Failure-Class trailers: 3ec08973 (fix(android)) and 79edabbf (fix(app)) both carry Failure-Class: none.
  • Freshness window: _isFresh() bounds last-known to 5 minutes and falls back to a medium-accuracy fresh fix; refreshes a stale last-known position before upload and uses a stale last-known when the current fix fails cover both directions in conversation_location_capture_test.dart.
  • Post-grant FGS start: the onNewlyGranted hook wired in capture_controller.dart (_startAndroidLocationForegroundTaskForegroundUtil.initializeForegroundService/startForegroundTask, Android-gated) closes the earlier home-page gap, with does not start a post-grant hook when permission was already granted pinning the negative case.
  • The AndroidManifest.xml comment and the doc-block in conversation_location_capture.dart documenting the while-in-use-only posture are accurate and match the code.

On the two red checks (Hygiene, Detect Desktop Swift Changes): not caused by this PR. Both fail in path detection with gcp-sa-key-ratchet: explicit trigger path does not exist: backend/agent-proxy/main.py — the checks manifest still referenced the retired backend/agent-proxy/ tree, which breaks preflight for every PR. That ratchet was already backed out on main in #12183, so a rebase onto current main should turn both green with no code changes needed.

One product item stays open for a human maintainer (label kept): streamRecording awaits captureAndUpload() before RecordingState.initialising, and the while-in-use prompt is deliberately outside the 3s budget — so on a first record start with location not yet granted, the OS permission dialog now appears before recording initializes. Defensible trade-off (the fix is never lost to a timeout), but prompt-at-record-start UX deserves explicit sign-off.


by AI on behalf of David — if you need David’s attention urgently, please @Git-on-my-level and escalate with need human response.

@Git-on-my-level
Git-on-my-level dismissed their stale review August 25, 2026 11:00

Dismissed as resolved at d125f9e: dead Position? null checks removed (late final + catch fallback, analyzer green) and Failure-Class: none trailers present on both fix commits.

@Git-on-my-level Git-on-my-level added the positive-signal Good PR — positive signal, not a formal approval label Aug 25, 2026
undivisible and others added 5 commits August 25, 2026 19:14
Prefer last-known and medium-accuracy fixes, and request while-in-use at record start, so Android conversation JSON gets coordinates without ACCESS_BACKGROUND_LOCATION.

Failure-Class: none
Add unit coverage for while-in-use prompting at record start and last-known-first upload so Android GPS attach does not require a device.
The while-in-use prompt at record start lived inside the 3s
totalTimeout, so the system dialog almost always lost and callers
moved on to microphone permission while it was still showing.

Keep the interactive grant unbounded, then apply totalTimeout only
to the GPS fix and upload.

Failure-Class: none
Address review: freshness window, permission-timeout fence, FGS after a newly granted while-in-use, and drop dead null checks the analyzer ratchet flagged.
Recording is the tap; location is metadata. Stop awaiting
captureAndUpload() on the record-start critical path so the OS
location dialog cannot hold RecordingState.initialising or stack
in front of the microphone prompt.

Failure-Class: none
@undivisible
undivisible force-pushed the fix/android-gps-location-nil branch from d125f9e to a4f8f1b Compare August 25, 2026 11:17
@undivisible

Copy link
Copy Markdown
Collaborator Author

@Git-on-my-level product call on the remaining item (your re-review at #12179 (comment)): do not block.

Recording is the tap; location is metadata. We will not hold RecordingState.initialising for the OS location dialog.

At a4f8f1b583 (rebased onto current main / #12183 7ebe8b1d):

  • streamRecording: set initialising → request microphone → start the recording path → then unawaited(captureAndUpload()). Location cannot stack in front of the mic dialog or block the button.
  • streamDeviceRecording: the same await is now unawaited, so device connect/start is not blocked. Location still PATCHes when the grant/fix lands. A short conversation can miss coords; accepted.
  • Permission prompt-at-record-start stays inside ConversationLocationCapture (denied → request while-in-use). We just stopped awaiting it on the record-start critical path.

Please drop needs-maintainer-review if that product item is now closed.


by AI on behalf of Max — if you need Max's attention urgently, please @undivisible and escalate with need human response.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a4f8f1b583

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

if (position == null) return false;
if (isCancelled()) return false;

return _upload(

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Fence uploads that outlive the capture timeout

When location acquisition completes within three seconds but the PATCH is slow or queued, Future.timeout returns false while this _upload future continues running because Dart timeouts do not cancel their source future. Fresh evidence despite the earlier thread resolution is that isCancelled() is checked only before _upload starts; makeApiCall permits writes to run for up to 300 seconds with a retry, and backend/routers/users.py::set_user_geolocation caches requests in arrival order without rejecting older timestamps. An earlier recording can therefore update Redis after a later recording has started or finalized; keep upload completion outside the acquisition timeout or sequence/cancel late uploads by capture identity.

Useful? React with 👍 / 👎.

@Git-on-my-level

Copy link
Copy Markdown
Collaborator

Reviewed at a4f8f1b583 (post-rebase head). The reordering resolves the product item kept open at d125f9e, verified in code:

  • Mic-first ordering holds: streamRecording() requests the microphone, starts the phone-mic path, and only then fires unawaited(captureAndUpload()) — the location dialog can no longer stack in front of the mic prompt or hold RecordingState.initialising. Same pattern on the batch path and in streamDeviceRecording.
  • d125f9e fixes intact at this head: the permission request still sits outside totalTimeout with the isCancelled/timedOut fence before upload; _isFresh() bounds last-known to 5 minutes with the stale→fresh→stale fallback ladder; the onNewlyGranted hook starts the Android foreground task only on a new grant (does not start a post-grant hook when permission was already granted pins it). The FGS isolate in foreground.dart mirrors the same last-known-first policy, and the manifest change is comment-only — no permission elements added.
  • Checks: the two stale-manifest reds cleared after the rebase exactly as predicted; Dart Analyze & Tests and Android Compile Smoke are green here.

One item remains before the label comes off, and it's the same placement question in new clothes — the unresolved bot finding from 09:22, still live at this head: HomePage's post-frame callback calls streamDeviceRecording unconditionally (page.dart:498-502), and it fires captureAndUpload() even when device == null (capture_controller.dart:1688). So on a fresh install with location denied, the OS location dialog appears on plain home-page entry rather than at a record tap; a user who denies it twice lands on deniedForever and coordinates are permanently nil with no in-app recovery. Gating the prompt on an actual record/device path (keeping check-only behavior for the no-device call) is the alternative. That, plus ratifying the accepted trade-off that a short conversation can miss coords, is the remaining product decision for @Git-on-my-level — code-side this is ready.

Minor, non-blocking: the 11:23 bot note on a slow PATCH outliving the 3s budget is real but low-impact — the isCancelled gate covers acquisition, not an upload that started within budget and runs long; sequencing uploads by capture identity would close it if it ever matters.



by AI on behalf of David — if you need David’s attention urgently, please @Git-on-my-level and escalate with need human response.

@kodjima33 kodjima33 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Confidence 4/5 (diff slightly over 300 lines, everything else checks out): clear multi-part root cause for missing Android GPS (permission never requested, timeout too short, no fallback on error), tests added, CI green. Verified not already fixed on main.

@kodjima33
kodjima33 merged commit 57349ee into main Aug 25, 2026
26 checks passed
@kodjima33
kodjima33 deleted the fix/android-gps-location-nil branch August 25, 2026 14:43
@undivisible

Copy link
Copy Markdown
Collaborator Author

@Git-on-my-level leftover from #12179 (comment) is implemented at b3e842d780.

Homepage / streamDeviceRecording(device == null) is check-only now — it no longer calls requestPermission. The OS location dialog only appears on an actual record or device start (streamRecording and streamDeviceRecording(device != null)), and still never re-prompts deniedForever. Mic-first ordering on streamRecording is unchanged.

The short-conversation miss (location PATCH landing after a brief recording ends) remains the accepted trade-off.

This PR already merged at 57349eef (22:43 HKT) before the leftover landed. The commit is on the recreated fix/android-gps-location-nil branch and is not on main yet.


by AI on behalf of Max — if you need Max's attention urgently, please @undivisible and escalate with need human response.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

android needs-maintainer-review Needs a human maintainer to sign off before merge positive-signal Good PR — positive signal, not a formal approval

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants