Files
buzz/mobile/test/features/age_gate
klopez4212 cb69ad9e4f Adapt iPhone Duo layouts, rail navigation, and native sheets (#8568)
Duo keeps conversations and Settings details open across closed, book
and flat postures. Book mode splits at the fold; flattening restores the
sidebar. Native rail controls, full-width navigation backdrops and
sheet-local safe areas keep content aligned. Ordinary iPhones remain
single-pane in portrait and landscape; tablet and Duo split layouts
remain enabled.

Includes the recovered preview's matching pane widths, Buzz empty-pane
mark, stable Settings chevrons, Bestie pane routing and Duo-only upward
New menu attachment. Current main's Activity redesign, Search content
fade and unread-navigation button are retained. Menu selection checks
sit beside their labels.

Shared mobile changes remain in scope: the native iOS status editor,
Appearance preview layout, avatar crop preservation, onboarding footer
layout, profile/invite sheet geometry and nested conversation
navigation. This PR is not exclusively Duo-gated. Nested navigator
observers preserve recording cancellation and navigation callbacks; crop
resizing preserves the selected image region. iOS 27.1 APIs remain
compile-time and runtime gated.

Validation on the reconciled source: Flutter analysis, Activity/Home
journeys, the full mobile test suite, file-size checks and Swift package
tests. The iPhone single-pane fix was also exercised on an iPhone 18 Pro
simulator before reconciliation. Fresh hosted CI and physical-device
confirmation of the reconciled build are separate and remain pending.

---------

Signed-off-by: kenny lopez <klopez4212@gmail.com>
Signed-off-by: Tom Brow <tomb@squareup.com>
Co-authored-by: Terp <5856f6900e8e0a4e0ea1f4f8d2ee33e4753d2119bc122f94ecafc660b46c0511@buzz.block.builderlab.xyz>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Tom Brow <tomb@block.xyz>
Co-authored-by: Tom Brow <tomb@squareup.com>
2026-11-12 19:00:58 +00:00
..

Age-check contract

Normal app, relay, and push startup do not depend on an age result. The only operation that can restrict access is a valid under-18 response from the current launch request. Errors, malformed responses, timeout, disposal, and late callbacks leave access allowed. There is one attempt per provider lifecycle, with no blocking retry or restart flow.

Production enforcement remains disabled. Dogfood builds can opt in with the Flutter define BUZZ_AGE_GATING_ENABLED=true. This enables the same notifier used by the native-channel and app tests. No real-device build is a PR prerequisite; actual OS prompts, signing, and account behavior will be checked in pre-release testing.

Automated evidence

  • age_signal_provider_test.dart: real method-channel codec, allowed/under-18 boundaries, malformed payloads, exceptions, missing plugin, timeout, late completion, concurrent callers, invalidation, disposal, and the build opt-in.
  • age_gate_app_test.dart: full app and push bootstrap remain mounted while the native response is pending or fails, and unmount only for a current under-18 response. Notification restoration failure does not gate app access.
  • Notification restriction leaves saved snapshots, signing keys, preferences, and remote leases intact. Only the confirming app process holds restriction authority; a later launch does not need storage restoration to allow access.
  • Swift and Kotlin adapter tests: platform-specific bounds are normalized conservatively, including contradictory ranges and extreme integers. Android SDK task tests exercise shared access, minor response delivery, both failure stages, and retired callbacks through the production request coordinator.
  • iOS simulator RunnerTests: the production method handlers deliver minor/error callbacks, allow notification restoration without app-group storage, and preserve snapshots through restriction, cleanup failure, and restoration.
  • Swift notification tests: real cross-process lock contention suppresses presentation. Process exit releases restriction without cleanup. Missing, stale, and inaccessible lock files cannot establish a restriction.

Run the Flutter age-gate suite both with and without the pre-release testing define. A test must fail if pending/error becomes restricted or an expired request can restrict. The implementation was mutation-tested for pending and error blocking.

An already-running platform consent dialog cannot be proven dismissible by Dart unit tests. That behavior remains part of pre-release testing validation before general re-enablement. Old releases that permanently saved push opt-out preferences did not record their cause; this change does not guess which opt-outs to reverse.