diff --git a/docs/public-launch-checklist.md b/docs/public-launch-checklist.md index 5588aa9..19ab7e5 100644 --- a/docs/public-launch-checklist.md +++ b/docs/public-launch-checklist.md @@ -119,14 +119,14 @@ as forward-only rather than receiving an invented database rollback. ## 6. Verify the deployed product -- [ ] Public HTTPS home, liveness, readiness, WebSocket upgrade, manifest, and +- [x] Public HTTPS home, liveness, readiness, WebSocket upgrade, manifest, and `assetlinks.json` return the expected production identity. - [ ] Registration, returning-user login, and settings linking complete against the production Google OAuth client and exact callback origin. - [ ] A production-generated authentication email reaches an external mailbox; sender identity and every URL use the production domain. - [ ] Browser Web Push reaches a real subscribed browser. -- [ ] The production Android build signs in, opens verified App Links, receives +- [x] The production Android build signs in, opens verified App Links, receives FCM, and performs user-started foreground location sharing on a physical device. - [x] The full two-person help flow passes: create, discover, accept, chat, diff --git a/docs/verification.md b/docs/verification.md index 468224c..873b19e 100644 --- a/docs/verification.md +++ b/docs/verification.md @@ -717,19 +717,19 @@ this audit. | Separate Activity mode | Implemented and tested | Coffee, cinema, walk, and hiking categories use a separate activity lifecycle. Domain and two-client LiveView tests cover creation, join request, organizer approval, capacity enforcement, public/pending/chat privacy, exact-location disclosure to approved users, group chat, blocking, completion, and zero impact on helper reputation. Activity and message reports expose only the linked group conversation to an audited moderator; moderators can hide and restore reported activities. | This does not guarantee participant identity or physical safety. | | Map and discovery | Implemented and browser-verified | The committed isolated Chromium suite rendered request and Activity maps, waited for MapLibre `idle`, and completed with no console, page, or request failures against a local PNG raster fixture. An earlier headed session rendered the configured OpenStreetMap tiles. | A production operator must configure a tile provider appropriate for its policy and traffic. | | Private matched chat | Implemented and cross-client verified | A message sent from the helper browser appeared in the requester's browser without reload. An earlier Android emulator run also sent a message that appeared in the requester browser in real time. | There is no unsolicited general-purpose inbox. | -| Consent-driven live tracking | Implemented and cross-client verified | On API 37, Android started `TrackingService` as a location foreground service with a persistent Stop notification. After Home minimized the Activity, an emulator coordinate change reached PostGIS. Notification Stop removed the service, notification, active session, and raw position. | Browsers stop with the page. Android has no `ACCESS_BACKGROUND_LOCATION`, unattended start, or route history. | +| Consent-driven live tracking | Implemented and cross-client verified | On API 37, Android started `TrackingService` as a location foreground service with a persistent Stop notification. The Play-delivered production build repeated the disclosure, foreground permission, minimized-app sampling, notification Stop, raw-position deletion, offline recovery, and process-recreation paths on a physical phone. | Browsers stop with the page. Android has no `ACCESS_BACKGROUND_LOCATION`, unattended start, or route history. | | Privacy settings | Implemented and browser-verified | The profile exposed hidden, approximate public, exact for active match, and explicit exact-public options. Blocking and current-position cleanup have automated tests. | Exact public location remains a user opt-in; legal privacy and retention text still requires jurisdiction-specific review before launch. | | Reputation and anti-abuse | Implemented at MVP level | Handover codes, two-party completion, double-blind reviews, unique-counterpart ranking, optional movement/proximity evidence, reports, blocks, abuse signals, and moderator audit paths have automated tests. | The system is not bot-proof and does not claim identity verification. No punitive numeric policy is enabled without measured and approved thresholds. | -| Account registration and sign-in | Implemented and browser-verified | Email registration is a single passwordless flow: it records the display name and acceptance once, sends a confirmation link, and does not duplicate a user on subsequent sign-in. Confirmed users can keep using magic links or add a password in settings. Google OpenID Connect registration, sign-in, link, unlink, replay prevention, verified-email enforcement, and account-ownership rules are covered by the 353-test suite. Real headed Chrome on the development origin exercised the Google callback, existing-account ownership email, one-time identity connection, and subsequent one-click Google login without creating a duplicate user. The application-generated authentication email was observed in Gmail from the development sender. | Production SMTP delivery and the production Google callback remain unverified. | -| Notifications and nearby alerts | Implemented and browser/physical-device verified in development | Users can configure push/email preferences, quiet hours, category/urgency/day/time filters, a private matching center, and 1/3/5/10/25 km radii. Durable inbox notifications and Oban delivery jobs are tested; public notification payloads omit chat text, exact coordinates, and the private saved-area label. The focused Chromium replay completed subscription, matching request, inbox delivery, navigation, and export. Real development Web Push delivery completed without a recorded error, and a real private FCM notification reached the physical Android development app. | Production Web Push and production Android FCM delivery remain unverified and require isolated production credentials. | +| Account registration and sign-in | Implemented and browser/physical-device verified | Email registration is a single passwordless flow: it records the display name and acceptance once, sends a confirmation link, and does not duplicate a user on subsequent sign-in. Confirmed users can keep using magic links or add a password in settings. Google OpenID Connect registration, sign-in, link, unlink, replay prevention, verified-email enforcement, and account-ownership rules are covered by the automated suite. Real headed Chrome exercised the development callback and identity-linking paths. The Play-delivered production build then completed production Google sign-in without a secondary ownership email or duplicate account. | A fresh production authentication-email delivery to an external mailbox remains a separate launch check. | +| Notifications and nearby alerts | Implemented and browser/physical-device verified | Users can configure push/email preferences, quiet hours, category/urgency/day/time filters, a private matching center, and 1/3/5/10/25 km radii. Durable inbox notifications and Oban delivery jobs are tested; public notification payloads omit chat text, exact coordinates, and the private saved-area label. Development Web Push and FCM delivery were exercised. The Play-delivered production build registered its FCM device, received one run-scoped production notification, and routed its tap to the in-app inbox; exact cleanup removed that notification and its jobs. | Production browser Web Push remains unverified. | | Social profiles | Manual links implemented; optional GitHub verification implemented and automated-tested | Manual links cannot set verification fields. The optional GitHub flow uses state, PKCE, a user-bound one-time session, unique provider ownership, and an audit record. The local protocol drill also performs real HTTP token/user exchanges without returning an access token to the application. | GitHub OAuth credentials are intentionally absent and are not required for registration or the help flow. The real external provider redirect/callback remains disabled and unverified; other providers remain manual/unverified. | | Support and content removal | Implemented and browser-verified | Public support, account deletion, general removal, and TAKE IT DOWN forms use separate audited workflows; public support remains pending and outside the staff queue until its private email link verifies the contact, while authenticated submissions use the account email immediately. Exact pending repeats are deduplicated, email/IP intake limits are independently configurable, and moderator-only operations can update verified cases. TAKE IT DOWN accepts URLs/text only and records a 48-hour review due time. Authenticated users can download an allowlisted JSON export, and moderators can run a read-only deletion relationship preflight. | The current product hosts no user media and does not claim TAKE IT DOWN coverage. Staffing, measured rate-limit thresholds, jurisdiction-specific legal classification, final retention rules, destructive account erasure/anonymisation, and identical-media-copy handling remain operational/legal work. | | Voluntary thanks | Implemented as an external optional link | A helper can expose an optional link after completion; the UI states that the platform does not process the payment. | The platform does not provide payments, escrow, refunds, tax reporting, or payment guarantees. | -| Android client | Local, development, test/staging, and production build identities implemented | The native packages `org.whoneedhelp.mobile.debug`, `org.whoneedhelp.mobile.development`, `org.whoneedhelp.mobile.staging`, and `org.whoneedhelp.mobile` are separated by build type and signing identity. Lifecycle, permission, deep-link, foreground tracking, recoverable main-page failure, notification-Stop, and Activity-destruction tests remain in place. Ephemeral signed development and production pipelines verify package IDs, certificates, unit tests, lint, APKs and instrumentation artifacts; production also verifies the signed AAB with Bundletool. The API 37 smoke verified the development App Link and WebView boundaries. A physical development device then passed magic-link login, bidirectional browser chat, real FCM delivery, foreground location sampling, Stop cleanup, and exact fixture cleanup. Evidence is `output/android-physical-development-e2e/physical-20260724-191948-1352510`. | Play registration/App Signing, production-device FCM delivery, unattended/background-permission tracking, and iOS are not complete. | +| Android client | Play Internal build verified on a physical phone | The native packages `org.whoneedhelp.mobile.debug`, `org.whoneedhelp.mobile.development`, `org.whoneedhelp.mobile.staging`, and `org.whoneedhelp.mobile` are separated by build type and signing identity. Google Play accepted AAB SHA-256 `03d39a9a08e9ca7569caccf1c7bd75e9349f7655935e7bbf23d1998cd37b3837` as `0.1.0 (1)` on Internal testing. The Play-delivered package passed installer/signature/domain verification, Google sign-in, verified App Links, production FCM delivery, foreground-location disclosure and lifecycle, notification Stop, offline recovery, process recreation, and exact fixture cleanup. | Closed testing and Production rollout have not been started. Android has no unattended/background-location permission; iOS is not implemented. | | Multiple web/worker instances | Implemented and locally failure/rollout-verified | The final isolated Compose drill passed BEAM crashes and sequential replacement with 3 web/2 worker replicas: all five nodes joined, PubSub passed, and 744/744 readiness requests succeeded. The project-owned kind cluster replaced all 2 web/2 worker pod UIDs under `maxUnavailable=0`; all four replacement pods joined, PubSub passed, and 363/363 samples ultimately succeeded. | Local PostGIS is a single instance. Production database HA, backups, and recovery are operator work and are not claimed complete. | | Local observability | Implemented and protocol-verified | Pinned Prometheus scraped the exact 3 web and 2 worker targets with a file Bearer credential; Grafana provisioned a healthy datasource and ten-panel web/worker/BEAM/Ecto/Oban dashboard; Alertmanager delivered firing and resolved webhooks for an induced scoped replica stop. | Local delivery does not establish production retention, notification-provider reliability, on-call policy, or measured alert thresholds. | | Encrypted local backup | Implemented and failure-verified | Pinned Restic streamed PostgreSQL custom format into pinned local MinIO with no host plaintext dump, passed full-data checking and a fresh-database restore, rejected a corrupted repository, and published no snapshot for an interrupted upload. The one-run MinIO project and volume were removed after retaining the non-secret evidence. | The drill proves the local mechanism, not off-site durability, database HA, or a production RPO/RTO/retention policy. | -| External protocol boundaries | Implemented and locally failure-verified | Assent/Req and Swoosh/gen_smtp paths have internal success/rejection/retry/replay/timeout coverage. Google OIDC discovery/authorization/token/JWKS with nonce and PKCE and the optional GitHub boundary are locally exercised through mocks. The development origin additionally exercised the real Google provider, an authenticated Brevo SMTP delivery observed in Gmail, real browser Web Push delivery, and real physical-device Android FCM delivery. The current push code includes provider-neutral HTTP delivery plus direct standards-based Web Push and FCM adapters with durable Oban retries and invalid-device cleanup. UniSender observations below are retained only as historical evidence and do not describe current wiring. | The real GitHub provider, production Google callback, production authentication-email delivery, production Web Push/FCM delivery, and APNs remain unverified. SMTP exactly-once delivery is not claimed. | +| External protocol boundaries | Implemented and provider-verified for the current pilot paths | Assent/Req and Swoosh/gen_smtp paths have internal success/rejection/retry/replay/timeout coverage. Google OIDC discovery/authorization/token/JWKS with nonce and PKCE and the optional GitHub boundary are locally exercised through mocks. Real development checks covered Google, authenticated Brevo SMTP, Web Push, and FCM. The Play-delivered build additionally completed production Google OIDC and production FCM delivery. The current push code includes provider-neutral HTTP delivery plus standards-based Web Push and FCM adapters with durable Oban retries and invalid-device cleanup. UniSender observations below are retained only as historical evidence and do not describe current wiring. | The real GitHub provider, fresh production authentication-email delivery, production browser Web Push, and APNs remain unverified. SMTP exactly-once delivery is not claimed. | ## Reproducible checks @@ -2192,3 +2192,49 @@ promoted. users and zero fixture requests while the pre-existing tester and its one push device remained present. The frozen hackathon test deployment and the public Git remote were not changed. + +# 2026-08-09 production operations recheck + +- The independent monitor host reported its timer loaded, enabled, active and + waiting. Its latest service execution exited successfully and recorded HTTP + 200 with the expected readiness payload. This is an observed external probe, + not an availability SLO. +- The production checkout remained at + `0ad9a5430e1a2e23ab976999faf1280bf53bcdc1`. Both environment validators + passed without printing secrets: all twelve readiness capability groups were + `READY`, with zero blocking items and zero local-only warnings. +- Public HTTPS home, liveness, readiness, manifest and Android association + endpoints returned HTTP 200. The readiness payload was + `{"status":"ready"}`; the WebSocket handshake returned HTTP 101. The + association response named `org.whoneedhelp.mobile` and published four + SHA-256 signing identities. +- The compact application container remained healthy with zero restarts and no + OOM kill. One point-in-time sample observed 189.3 MiB container memory, 25 + PIDs and 0.32% CPU. The host reported 1,224,523,776 bytes available memory + and 108,116,156,416 bytes available on `/`. These are observations, not + minimum requirements or capacity limits. +- The only six warning matches in the preceding hour were module-redefinition + warnings caused by the run-scoped physical verification RPC. No error, + exception, stacktrace or crash term matched in the same log interval. +- The local encrypted off-site backup timer was loaded, enabled, active and + waiting. Its latest service execution exited successfully after creating + Restic snapshot + `869e3e3a7444d726daef7e9afbdcc9ee082962a6121ec2e29c942600396fd13c`. + Restic checked all 8 snapshots and 16 packs with no errors; the isolated + restore drill observed 34 application tables, 24 schema migrations, + PostgreSQL 18.4 and PostGIS 3.6.4. Evidence is retained at + `output/production-operations/20260808T210010Z-2802200/` with directory mode + 0700 and file modes 0600. +- The retained production browser replay for this exact source revision passed + both two-user flows in 52.3 seconds. Readiness was healthy before and after, + every tracked product-table count matched its pre-run value, and the fixture + prefix count was zero after cleanup. Evidence remains at + `output/production-full-e2e/production-e2e-20260808-0ad9a54/`. +- A recoverability audit found that the healthy shared edge container used the + immutable image ID + `sha256:e450c305cc0a729406392dad5064f835a6f05ef45b787519023e12c8d65cadd2`, + while the production environment referenced a removed tag for the same edge + build. The missing tag `who-need-help:caddy-production-921e04b36080` was + restored to that exact running image ID. Compose configuration then passed; + edge, test application and test database start timestamps were unchanged, + and both production and frozen-test readiness remained HTTP 200.