System analysis β full-spectrum review β
Historical audit snapshot from 2026-06-11. The live incidents in Β§1 (A-001/A-002 cron and webhook 503s) were not re-verified afterwards; re-check edge logs before treating them as open or closed. Its repository-ownership, function-count, CI, and open-gap statements are superseded by
docs/CROSS_PLATFORM_PARITY.md,contracts/backend/function-ownership.json, and the current protected workflows. Retain it as audit history only.
Full-spectrum audit of the Flutter app + its live Supabase backend, 2026-06-11, at commit b34b42f (HEAD, main). Method: 3 evidence-gathering agents + 10 dimension finders + 5 adversarial verifiers + completeness critic + register reconciler (20 agents, ~2.4M tokens), plus read-only live checks of project jrsgosnnyjonxaesqtln (advisors, tables, functions, migrations, logs, pg_policies). Severity: S1 crash/blocker Β· S2 broken feature Β· S3 UX/maintainability/perf/docs Β· S4 polish. SI = static inference (not executed; capped at S3 by rule).
Verdict: B. The codebase is production-ready and its fundamentals are genuinely good β disciplined repository layer (zero raw repo construction in features, 111/112 repos self-host providers), excellent .single()/write-validation hygiene, consistent realtime cleanup, tested route policies, clean config, and an i18n/bidi system that mostly works. What pulls it down is not code quality but (1) live operational incidents nobody is paged for, (2) a delivery safety net that is currently red or advisory, and (3) accumulated scale/maintenance debt now overtaken by real data growth. 83 raw findings β 4 refuted, 1 absorbed into registers, 78 confirmed (merged to 74 register rows below + 6 critic-minted).
1. Executive summary β top 5 risks β
- Scheduled communications are down in production right now (A-001, A-002, S2). Every cron-driven send pipeline β scheduled emails, scheduled WhatsApp, drip campaigns, appointment/valuation-visit reminders, scheduled posts β has been returning 503 (
deployment_id:nullβ requests never reach a healthy deployment) every minute for the whole 24h log window, and inboundwhatsapp-webhookshows intermittent 503s with no 200s observed. The app keeps accepting schedules with no failure surfacing. The reliability monitor is logginginbound_no_dispatchincidents, but nothing escalates. - The delivery safety net is frayed (A-003, A-004, A-040..A-047). Goldens lane red at HEAD (8 stale baselines since the i18n Round-2 sweep), Android e2e lane dead (11 consecutive QEMU hangs since 2026-06-09 β the S-006 mitigation's CI vehicle provides zero signal),
mainhas no branch protection (verified via API: 404), no lockfile enforcement in any lane, and the Play promote step is the one masked step with no anti-masking report. - Security verification gap inherited from the repo split (A-019, S-010 escalated). The four highest-risk-named edge functions (
update-user-password,invite-user,bulk-insert,import-voter-names) runverify_jwt=falseand could not be source-audited from here (bundle fetch failed; source lives inbusami/aldilaijanre). The six sensitive functions that could be fetched all verified SAFE (real JWT validation + admin role checks, timing-safe API keys, HMAC webhooks) β the pattern is good, but these four must be audited from the web repo. - Correctness-at-scale debt overtaken by live data (A-005, A-009..A-011). The property-registry screen searches only the newest 500 of 6,452 live rows; dashboard aggregates compute over silently truncated result sets; count queries transfer full rows (19k-row notifications table on every realtime event).
- Database-side performance debt (C-002). 1,029
auth_rls_initplanWARNs across 283 tables (per-rowauth.*()re-evaluation β includesrealtime.messages, taxing every broadcast), 252 unused indexes, 17 unindexed FKs, and the Auth server capped at 10 absolute connections (directly relevant to the S-009 refresh-storm history). Fix is largely one mechanical migration.
Scorecard preview: all 10 dimensions graded B independently. No S1 findings. 4 claims refuted by adversarial verification (Β§10) β including two that looked like S1/S2 security holes and were empirically disproven against live RLS.
2. System map β
| Layer | Facts (verified) |
|---|---|
| App | 558 Dart files; 41 feature modules (~80 screens); Riverpod 3.0.3 hand-written (285 providers co-located with repos, 191 autoDispose); GoRouter 17.2.3 (router.dart 1,917 lines / 235 routes); 2 brands, ar/en + bidi layer |
| Data | 112 repositories (111 self-host providers); 56 model files + inline row classes in 110 repos; 343 .from() calls β 107 distinct tables; 40+ .rpc() sites in 19+ files; 31 .single() / 34 .maybeSingle() |
| Backend | Supabase jrsgosnnyjonxaesqtln: ~220 public tables (ALL RLS-enabled), 119 edge functions (ALL ACTIVE; 19 in the invoke inventory + 5 SSE/raw-HTTP slugs missed by it), 1,231 migrations, postgis/pgvector/pg_cron live |
| Live data | properties_base 3,597 Β· valuations_base 4,419 Β· property_registry 6,452 Β· notifications 19,211 Β· hermes_embeddings 19,289 Β· registry_voters 769,719 (verified admin-only RLS) Β· whatsapp_messages 2,778 |
| Integrations | Hermes AI gateway (SSE), WhatsApp Meta Cloud coexistence (29 tables), 4 IMAP mailboxes, PACI/Google/Baladia maps, FCM, Sentry 8.14, Mixpanel |
| Quality | 289 test files (~1,045 tests; 89-test slice re-verified green); 7 GitHub workflows; analyzer: 102 info-only issues |
Diagrams: system context, app layering, WhatsApp inbound flow, and CI/CD pipeline were rendered in the analysis session (see chat); regenerate on demand.
3. Method and coverage limits β
- Phase 0: pinned-SDK analyze +
pub outdated+ 89-test slice + grep metrics; live Supabase read-only sweep (security+performance advisors, tables, 119 functions, migrations, extensions, logs Γ4 services, publishable keys, onepg_policiesSELECT); live-source audit of 10 sensitiveverify_jwt=falsefunctions. - Phase 1: 10 finders (ARCH/DATA/SEC/STATE/PERF/I18N/TEST/CI/RES/DEP), each β€15 claims, evidence mandatory.
- Phase 2: 5 adversarial verifiers (partitioned, SEC isolated) re-read every cited line and actively attempted refutation β including live RLS probes, resolved-package source reads, and
gh apichecks; completeness critic spot-read 3 unsampled modules (bundles, call_logs, voice) β low sampling error (unsampled modules follow the same house patterns; defects found there were lower-stakes instances of already-claimed classes). - NOT covered: edge-function source other than the 10 fetched (web repo owns it); React SPA + PDF surfaces; device-only QA (mic, push e2e, biometrics); dynamic a11y (VoiceOver/TalkBack); Kuwaiti-Arabic translation quality (REMAINING_WORK C.1 β needs native speaker); log conclusions limited to a 24h window.
4. Findings register β
Status: confirmed = survived adversarial verification; downgraded = confirmed with reduced severity (reason in Β§10); critic-minted rows marked β. Three duplicate findings independently raised by 2β3 finders were merged (noted in evidence).
S2 β broken features / live incidents β
| ID | Sev | Dim | Area | Finding | Evidence | Status |
|---|---|---|---|---|---|---|
| A-001 | S2 | RES | ops/comms | Scheduled WhatsApp/drip/email/reminder sends down live: cron-driven functions 503 every minute for β₯24h (deployment_id:null); app keeps accepting schedules, no failure surfaced to staff | live edge logs 2026-06-11; process-scheduled-emails, send-scheduled-whatsapp, process-drip-campaigns, check-*-reminders, process-scheduled-posts | confirmed |
| A-002 | S2 | β | ops/whatsapp | Inbound whatsapp-webhook degraded: intermittent 503s, zero 200s observed in 24h window; Meta retries mask some loss; inbound_no_dispatch reliability incidents actively logging (35 rows) | live edge logs; whatsapp_reliability_incidents | confirmed (live) |
| A-003 | S2 | TEST | CI/goldens | Goldens lane red at HEAD: 8 baselines stale after i18n Round-2 sweep; gate stays red until manual macOS regeneration | gh run 27305212987 (headSha b34b42f, failure); valuations + transactions card goldens | confirmed |
| A-004 | S2 | TEST | CI/e2e | Android e2e lane dead: 11 consecutive QEMU emulator hangs since 2026-06-09 incl. HEAD β S-006's mitigation vehicle provides zero signal | gh run list e2e.yml; runs 27305213245, 27297765456 | confirmed |
| A-005 | S2 | DATA | admin/registry | Property-registry screen searches/filters only the newest 500 of 6,452 live rows; summary stats reflect the capped fetch | property_registry_repository.dart:128-136,161; property_registry_screen.dart:56 | confirmed |
S3 β architecture & data layer β
| ID | Sev | Dim | Area | Finding | Evidence | Status |
|---|---|---|---|---|---|---|
| A-006 | S3 | SEC | edge fns | 4 highest-risk-named verify_jwt=false functions (update-user-password, invite-user, bulk-insert, import-voter-names) internal-auth UNVERIFIED β source only in web repo; 6 peers fetched + verified SAFE | evidence pack Addendum A; ties to S-010 | downgraded (no demonstrated gap) |
| A-007 | S3 | SEC | auth/ops | Phone-OTP sign-in had a live incident: /otp 500 Γ12 ("unavailable due to hook"); auth-sms-hook 500s when SEND_SMS_HOOK_SECRET unset; self-quieted β transient, but primary staff sign-in has no alerting | live auth logs ~15h pre-check; hook source verified | downgraded (transient) |
| A-008 | S3 | ARCH | layering | 10 feature screens bypass the repository layer with raw Supabase.instance.client.from() queries, incl. a direct insert | global_search_screen.dart:71-141; account_deletion_screen.dart:79,138; +8 | confirmed |
| A-009 | S3 | ARCH | modularity | Cross-feature dependency cycles: clientsβcrm, mailboxβcomms, crmβpublicβvaluationsβcrm | clients_list_screen.dart:24, buyers_list_screen.dart:27, etc. | confirmed |
| A-010 | S3 | ARCH | navigation | Monolithic router.dart: 1,917 lines, 235 GoRoutes, imports 100+ screens from all features | lib/core/navigation/router.dart | confirmed |
| A-011 | S3 | ARCH | screens | 10 god screens β₯980 lines with workflow logic in widgets, incl. two parallel 1,200/1,763-line property intake screens | property_form_screen.dart 1,763; hermes_dashboard_screen.dart 1,658; +8 | confirmed |
| A-012 | S3 | DATA | metrics | Audit-tooling note: .rpc( grep metric was wrong β 40+ RPC sites in 19+ files (generic .rpc<T>() form); no rpc-inventory guard exists | comparables_repository.dart:98; properties_repository.dart:186,261; offline_write_queue.dart:323 | confirmed |
| A-013 | S3 | DATA+PERF | queries | Count-only reads use .select().count(exact) transferring up to max-rows of data instead of head-only counts β incl. full rows from the 19k-row notifications table on every realtime badge refresh | notifications_repository.dart:40-46; reports_repository.dart | confirmed (merged 2 claims) |
| A-014 | S3 | DATA | dashboards | Client-side aggregates over silently truncated result sets produce wrong dashboard numbers at current data volume | reports/transactions repos, unordered limit(5000) slices | downgraded (one sub-claim refuted) |
| A-015 | S3 | DATA | findOrCreateConversation check-then-insert race (no onConflict) for contacts/conversations; drafts repo does it correctly with upsert | whatsapp_repository.dart:321-368 | confirmed SI | |
| A-016 | S3 | DATA+RES | offline | OfflineWriteQueue flush() not re-entrancy-guarded; rewrites queue from pre-flush snapshot β overlapping triggers double-apply; enqueue during flush silently dropped | offline_write_queue.dart:124-146,273-288; app_shell.dart:79-83 | confirmed SI (merged 2) |
| A-017 | S3 | DATA | offline | Offline visit edits are last-write-wins with no staleness guard β late flush silently overwrites newer online edits | offline_write_queue.dart:292-310 (queuedAt never used) | confirmed SI |
| A-018 | S3 | RES | offline | Offline enqueue triggers on ANY exception: server rejections (RLS/CHECK/4xx) masked as deferred success and retried forever | valuation_visits_repository.dart:210,240 untyped catch | confirmed |
| A-019 | S3 | DATA | error UX | Silent-empty error mapping: mailbox list() swallows all exceptions into an empty inbox; same in whatsapp_marketing + reports + contract_signing meta | mailbox_repository.dart:213-216; whatsapp_marketing_repository.dart:182-205 | confirmed |
| A-020 | S3 | DATA+STATE+RES | realtime | realtimeNotificationsProvider is dead code with a wrong filter column (recipient_id vs schema user_id) β never watched anywhere; live notification badge realtime never activates. Found independently by 3 finders | realtime_provider.dart:25-49 | confirmed (merged 3 claims) |
S3 β state, performance, i18n β
| ID | Sev | Dim | Area | Finding | Evidence | Status |
|---|---|---|---|---|---|---|
| A-021 | S3 | STATE | auth | Session-identity providers never invalidated on sign-out/in (currentUserProvider, currentUserProfileProvider) β second user on same device sees first user's identity until restart | auth_providers.dart:28-30; current_user_profile.dart:43-45; settings_screen.dart:93-104 | downgraded SI |
| A-022 | S3 | STATE | async | 35 unguarded ref.read/invalidate-after-await sites across 25 files β throws if widget unmounts mid-mutation, skipping cache refresh (critic found more in unsampled call_logs β undercount) | multiline grep; exemplar valuations_kanban_screen.dart:255-275 | confirmed SI |
| A-023 | S3 | STATE | tooling | riverpod_lint/custom_lint declared but never run β no analyzer plugin registration, no CI invocation | pubspec.yaml:249-256; analysis_options.yaml; grep .github | confirmed |
| A-024 | S3 | STATE | feeds | applyQuery/refresh silently dropped while a page fetch is in flight in both accumulating feed controllers | properties_list_provider.dart:81-121; transactions clone | confirmed SI |
| A-025 | S3 | PERF | registry | Registry counters download thousands of id rows (rows.length as count) and eagerly build up to 200 cards in a plain ListView rebuilt per keystroke | property_registry_repository.dart:144-177 | confirmed SI |
| A-026 | S3 | PERF | web startup | Web cold start ships ~2.2MB / 13 bundled font weights + render-blocking Google Fonts CSS for 3 families used by one admin screen | pubspec.yaml:339-371; web/index.html:34-36 | confirmed SI |
| A-027 | S3 | PERF | i18n startup | 1.26MB translation JSON decoded + flattened synchronously on the UI isolate at startup and on every locale switch (cache:false); every t() runs bidi regexes | app_localizations.dart:91-108 | confirmed SI |
| A-028 | S3 | I18N | ar bundle | ar.json missing the entire aiAnalyst.suggestions block (6 keys) β Arabic AI Analyst users get zero suggestion chips | parity script: en 23,756 vs ar 23,750 keys | confirmed |
| A-029 | S3 | I18N | tooling | Audit blind spot: _dynamicPrefixes allowlist skips ar/en parity for runtime-built keys β all 14 CI gate tests pass while ar bundle is missing keys (A-028 proves it) | tool/audit_i18n_keys.dart:33-75 | confirmed |
| A-030 | S3 | I18N | properties | BuildingCompositionView renders Arabic-only usage/unit labels + 'Ω Β²' regardless of locale, incl. public screens | building_composition_view.dart:82-149 | confirmed |
| A-031 | S3 | I18N | RTL | client.phone rendered without bidi isolation in request_form picker β exact bug class commit 2effd86 fixed elsewhere (deal_form does it right) | request_form_screen.dart:735-740 vs deal_form_screen.dart:631-638 | confirmed |
S3 β testing, CI/CD, resilience, dependencies β
| ID | Sev | Dim | Area | Finding | Evidence | Status |
|---|---|---|---|---|---|---|
| A-032 | S3 | TEST | guards | edge_function_inventory_test is tautological (asserts countβ₯20 + 2 memberships β cannot fail when a new invoke is added) AND the inventory misses 5 functions mobile depends on: 4 raw-HTTP SSE slugs (incl. Hermes fallback ai-assistant) + google-tiles | edge_function_inventory_test.dart:32-38; sse_chat_edge_stream.dart:53 | confirmed (merged 2) |
| A-033 | S3 | TEST | coverage | 31/112 repositories have no dedicated test file β incl. 5 of the 12 largest (whatsapp 617 lines, reports 563, properties 539, finance 533, hermes 484) | test-tree diff | confirmed |
| A-034 | S3 | TEST | coverage | 3/41 feature modules zero test coverage: comms, crm, interactions β comms untested anywhere | ls diff; grep over test/ | confirmed |
| A-035 | S3 | CI | delivery | Play "Promote Internal β Alpha" is the one masked step with NO anti-masking report (continue-on-error without id: β outcome unreadable) | flutter-android.yml:236-268 | confirmed |
| A-036 | S3 | CI | governance | main has no branch protection / rulesets β every CI gate advisory; untested pushes fan straight into store-delivery lanes | gh api: 404 "Branch not protected"; rules [] | confirmed |
| A-037 | S3 | CI | reproducibility | No --enforce-lockfile in any lane β CI/release binaries can silently re-resolve away from pubspec.lock (the lock drift in the working tree shows it happens) | 5 workflows, bare flutter pub get | confirmed |
| A-038 | S3 | CI | delivery | Store uploads on EVERY main push with the static pubspec version β duplicate-version rejections are routine, training operators to ignore the anti-masking reports | flutter-android.yml:101-234; flutter-ios.yml:99-310 | confirmed SI |
| A-039 | S3 | CI | contract | Contract drift gate: no schedule trigger (unbounded detection latency) and silently no-ops green when MONOREPO_FETCH_TOKEN absent | contract.yml:12-44 | confirmed |
| A-040 | S3 | RES | AI/SSE | Hermes/edge SSE chat has no connect or inactivity timeout β hung endpoint leaves chat streaming forever | hermes_chat_repository.dart:254; sse_chat_edge_stream.dart:67 | confirmed SI |
| A-041 | S3 | RES | AI/SSE | SSE close without [DONE] treated as clean completion β truncated AI answers rendered and persisted as complete | hermes_chat_repository.dart:338-339; ai_chat_screen.dart:354-357 | confirmed SI |
| A-042 | S3 | RES | offline | OfflineDraftQueue pilot unwired AND its enqueue crashes (d.toJson tear-off passed to jsonEncode); doc header in voice_notes_screen also stale | offline_draft_queue.dart:85 | confirmed |
| A-043 | S3 | RES | offline | No connectivity-restore flush trigger despite the queue contract documenting one; connectivity_plus listening is one screen-local notifier | offline_write_queue.dart:91 vs grep .flush() (3 manual sites) | confirmed |
| A-044 | S3 | DEP | AI | Deprecated google_generative_ai retained for dead GeminiService hardcoding retired gemini-1.5-flash; pubspec comment misdocuments it as powering AI Hub (edge-backed since) | pubspec.yaml:23-27 vs ai_hub_repository.dart:1-2 | confirmed |
| A-045 | S3 | DEP | web | Discontinued transitive js 0.6.7 pulled solely by flutter_secure_storage 9.x web plugin (10.x drops it); blocks wasm future | pubspec.lock:1063; pub deps | confirmed |
| A-046 | S3 | DEP | push | Firebase stack a full major behind (core 3β4, messaging 15β16); upgrade couples to raising iOS 13.0 deployment floor | pubspec.yaml:74-75; project.pbxproj:651 | confirmed SI |
| A-047 | S3 | DEP | maps/crash/test | Upgrade debt cluster: flutter_map 7β8 (+cluster+vector_map_tiles coupling), sentry_flutter 8β9 (v8 in maintenance), golden_toolkit DISCONTINUED (3y), platform-plugin majors (local_auth 2β3, file_picker 8β11, share_plus 10β13, record 5β7, geolocator 13β14) while targeting Android 16 | pubspec.yaml; pub outdated table | confirmed (merged 4 DEP claims) |
| C-002 | S3 | β | database | DB-side perf debt: 1,029 auth_rls_initplan WARNs / 283 tables (incl. realtime.messages), 252 unused indexes, 17 unindexed FKs, 1 duplicate index, Auth server capped at 10 absolute connections | live performance advisors (evidence pack Addendum B) | confirmed (live) |
| C-004 | S3 | β | a11y | Accessibility near-absent statically: ~29 Semantics-related occurrences across 15 files for a 200+-screen app; REMAINING_WORK B.3 only half device-blocked | grep; REMAINING_WORK.md B.3 | confirmed (static) |
S4 β polish β
| ID | Sev | Dim | Area | Finding | Evidence | Status |
|---|---|---|---|---|---|---|
| A-048 | S4 | ARCH | structure | Inconsistent module substructure (3/40 have providers/, mixed flat-vs-screens/), stray helpers at layer roots | ls -d lib/features/*/providers | confirmed |
| A-049 | S4 | ARCH | shell | Comms badge computes one int from β€200 full conversation rows + drafts + mailbox counts on every shell build | comms_badge_provider.dart:10-27 | confirmed SI |
| A-050 | S4 | ARCH | models | Model layer split across two homes (56 model files vs inline row classes in 110/112 repos); one strict-parse outlier | grep fromJson distribution | confirmed |
| A-051 | S4 | DATA | queries | 2/31 .single() sites on 0-row-capable paths (raw PGRST116 surfaced); other 29 disciplined | ai_conversations_repository.dart:173-178; tasks_repository.dart:126-135 | confirmed SI |
| A-052 | S4 | SEC | deep links | resolveNativeDeepLinkRoute accepts any https host (no allow-list) despite doc implying aldilaijan.com only β output still passes the route normalizer | deep_links.dart:28-34 | confirmed SI |
| A-053 | S4 | STATE | caching | ref.keepAlive() before fetch caches first-failure for the session (4 reference-data sites; riverpod 3.0.3 retry softens) | reference_data_repository.dart:340-346 +3 | downgraded SI |
| A-054 | S4 | STATE | providers | Dead family providers with unstable keys (TransactionsQuery no ==; List<String> key + keepAlive) | transactions_repository.dart:310-313; dynamic_dropdowns.dart | confirmed |
| A-055 | S4 | STATE | rebuilds | AppPreferences: no value-equality + un-selected watches at MaterialApp + ~15 screens β any pref write rebuilds the world | app_preferences.dart:71-167; app.dart:27 | confirmed SI |
| A-056 | S4 | STATE | lifecycle | Non-autoDispose providers pin autoDispose mailboxAccountsProvider alive app-lifetime; accumulating feed notifiers retain full row lists across sign-out | mailbox_providers.dart:22-86; properties_list_provider.dart:136-139 | confirmed (merged 2) |
| A-057 | S4 | PERF | images | PropertyCard cover + HeroHeader bypass BrandedNetworkImage memCacheWidth convention (latent full-res decode) | property_card.dart:184-193; hero_header.dart:127-131 | confirmed SI |
| A-058 | S4 | PERF | voice | Voice-notes list is an unbounded N+1 (serial signed-URL per note, no limit) β latent: table empty in production | voice_notes_repository.dart:58-122 | downgraded |
| A-059 | S4 | I18N | tooling | isAr-ternary gate only scans /screens/ β bilingual literals persist in data layer (user-visible content prefixes) | audit_isAr_hardcoded_test.dart:19-22; ai_content_repository.dart:44-46 | confirmed |
| A-060 | S4 | I18N | forms | 4 hardcoded format hints (YYYY-MM-DD, email) bypass the bundle pattern | property_form_screen.dart:878,1205; inspector_portal_screen.dart:635 | confirmed |
| A-061 | S4 | I18N | ar bundle | ~115 ar.json values still English (mostly admin widget-gallery; incl. 'RELATIONSHIP NETWORK' subtitle) | parity script: 177 byte-identical en==ar | confirmed |
| A-062 | S4 | TEST | contract | Contract gate silently disappears if MONOREPO_FETCH_TOKEN rotates (job no-ops green, warning only) | contract.yml:39-44 | confirmed |
| A-063 | S4 | TEST | CI cost | Full unit suite runs 4Γ per main push (android+ios+web+goldens-smoke) β flaky test reds 4 lanes | three workflows, identical flutter test | confirmed SI |
| A-064 | S4 | CI | secrets | Secrets interpolated directly into run-script bodies (keystore base64, key.properties heredoc) instead of env indirection | flutter-android.yml:131-137 | confirmed |
| A-065 | S4 | CI | caching | Gradle/Android caching absent (pub cache IS cached via flutter-action; gradle not) | e2e.yml/android.yml post-job logs | downgraded |
| A-066 | S4 | CI | lanes | iOS sync step omits --check; iOS has no pull_request trigger (breakage detected post-merge) | flutter-ios.yml:87-94 | confirmed |
| A-067 | S4 | DEP | charts | fl_chart pre-1.0 (0.69.2) on 5 production chart sites; 1.2.0 stable available | pubspec.yaml:86 | confirmed |
| A-068 | S4 | DEP | overrides | device_info_plus 12.3.0 exact-pin justification stale (cited Xcode 16.2 failure; CI now on Xcode 26) | pubspec.yaml:214-227 | confirmed SI |
| A-069 | S4 | DEP | tooling | patrol 3.20β4.6 and very_good_analysis 7β10 frozen on old lines | pubspec.yaml:242,247 | confirmed SI |
| C-003 | S4 | β | public forms | property_submissions anonymous-insert surface unverified for abuse protection (the analogous valuation_requests claim was REFUTED β RLS blocks it; this table needs the same one-query check) | critic spot-read of /submit-property | needs verification |
| C-005 | S4 | β | privacy | Mixpanel tracks anonymous public-tool visitors with no consent gate/opt-out; Kuwait DPPR/CITRA exposure unassessed | mixpanel_analytics_client.dart; public_visitor_service.dart | confirmed (static) |
| C-006 | S4 | β | docs | Register/doc drift: voice_notes_screen header claims table/bucket "not shipped" (both live); REMAINING_WORK prose sections stale vs this audit | voice_notes_screen.dart header | confirmed |
5. Per-dimension grades β
| Dimension | Grade | One-line justification |
|---|---|---|
| Architecture | B | Two-layer design real and enforced (0 repo constructions in features); debt = cycles, 1,917-line router, 10 god screens, 10 bypass screens |
| Data layer | B | Excellent .single()/write-validation/realtime hygiene; debt = scale-overtaken caps, offline-queue races, silent-empty catches |
| Security | B | RLS-first model verified live (registry_voters, network_*, valuation_requests all held under attack); debt = 4 unauditable functions, transient OTP incident unalerted |
| State (Riverpod) | B | 191 autoDispose, Equatable family keys mostly disciplined; debt = session-provider invalidation, 35 after-await sites, riverpod_lint unwired |
| Performance | B | Lists mostly bounded, images mostly cached; debt = head-count queries, web font/i18n payloads, registry screen; DB-side debt is the bigger half (C-002) |
| i18n/RTL | B | 23.7k keys, bidi layer, CI audit gates; debt = one missing ar block the tooling can't see, Arabic-only composition labels, 1 bidi regression |
| Testing | B | 1,045 green tests, 89-test slice verified; debt = red goldens lane, dead e2e lane, tautological inventory guard, comms/crm untested |
| CI/CD | B | 7 lanes with genuine anti-masking pattern; debt = unprotected main, no lockfile enforcement, promote-step mask, version-bump friction |
| Resilience | B | Error-state widgets + circuit breaker exist; debt = offline queue not production-grade, SSE timeouts absent, dead realtime provider, no scheduled-send failure surfacing |
| Dependencies | B | Pinned SDK + annotated pubspec; debt = 1 discontinued direct dep (golden_toolkit), 1 discontinued transitive (js), firebase/sentry/maps majors, dead google_generative_ai |
6. Live backend verification summary β
- 119/119 edge functions ACTIVE; all 19 inventory functions present.
verify_jwt=falseon ~96 β by design (internal auth verified SAFE on all 6 fetchable sensitive functions; 4 unfetchable β A-006). - Advisors: security = S-011 WARNs persist as documented/intentional; S-012 = 11 tables (refreshed list in Β§7);
cron.jobanon-policy WARN investigated via pg_policies β noise (qualusername = CURRENT_USER). Performance = Β§C-002. - Migrations: 1,231; S-011 revoke migration present (live id 20260609223608). 4 taxonomy migrations of 2026-06-10 verified consistent with repo choice catalogs (no drift β DATA finder checked).
- Logs (24h): edge 503 cluster (A-001/A-002) + auth OTP incident (A-007); PostgREST all 200/204; postgres routine (collation-version warnings = one
REFRESH COLLATION VERSIONof hygiene). - Keys: env/dev.json anon key matches live; publishable keys exist for hermes/cloudflare/CI consumers.
7. Register reconciliation (proposed β registers not edited by this audit) β
| Register row | Current | Proposed |
|---|---|---|
| S-006 | mitigated | regressed β the e2e CI lane carrying the mitigation is dead (A-004); un-skipped Patrol tiers give zero signal until the lane is fixed |
| S-010 | documented | open/escalated β mirror gap now blocks internal-auth audit of 4 high-risk functions (A-006); audit them from busami/aldilaijanre, then re-close |
| S-012 | open | open, refreshed 2026-06-11 β live list: 7 _canon_backup_*/_phase5_* scratch tables (incl. the 25-day-old OTP backup, 7 rows) + 4 documented service-role-only whatsapp queue tables; 5 scratch tables also lack PKs; action = drop/archive the scratch set |
| S-001/S-002/S-009/S-011, F-004 | β | confirmed unchanged (live evidence) |
| F-008 | fixed | unchanged; A-031 is a NEW instance of the same bug class elsewhere, not a regression |
8. Prioritized recommendations β
P0 β this week (ops/incidents):
- Restore the scheduled-send pipeline + inbound webhook (A-001/A-002): the
deployment_id:null503 signature suggests functions failing at boot (bad shared-module deploy or missing secret) β redeploy/inspect from the web repo; add an alert on cron-function failure (the reliability-incidents table already has the data). - Regenerate golden baselines (goldens.yml manual dispatch on macOS) to un-red the lane (A-003).
- Fix or quarantine the e2e lane (A-004) β 11 QEMU hangs; pin a known-good emulator image/API or pause the lane so red β noise; reflect S-006 status.
- Audit
update-user-password,invite-user,bulk-insert,import-voter-namessource in the web repo (A-006). - One DB hygiene migration: wrap RLS policies in
(select auth.*())(C-002, mechanical), drop_canon_backup_*/_phase5_*scratch tables (S-012), switch Auth connections to percentage allocation.
P1 β next sprint(s): 6. Registry at scale (A-005/A-025): server-side search/filters + head-only counts; same head-count fix for notifications badge (A-013). 7. Offline queue hardening (A-016/A-017/A-018/A-043): in-flight flag, re-read queue before rewrite, typed catch (only network errors enqueue), connectivity-restore flush, staleness guard; decide OfflineDraftQueue's fate (A-042). 8. SSE robustness (A-040/A-041): connect+inactivity timeouts; treat missing [DONE] as truncation with retry affordance. 9. Auth-state provider invalidation on sign-in/out (A-021); fix the dead realtime provider or delete it and wire the badge channel (A-020). 10. CI governance (A-035..A-039): branch protection on main, --enforce-lockfile, id: + report for the promote step, auto-bump build number per delivery (the duplicate-version noise is training operators to ignore reports), contract.yml schedule trigger + fail-on-missing-token. 11. i18n (A-028..A-031): add the 6 ar keys, make _dynamicPrefixes contract machine-checked, localize BuildingCompositionView, .forDisplay on request_form phone.
P2 β backlog: 12. Dependency train in order: flutter_secure_storage 10 (kills discontinued js) β sentry 9 β firebase 4/16 (+iOS floor) β maps 8 cluster β fl_chart 1.x β golden_toolkit replacement (e.g. alchemist) β patrol 4/VGA 10. Delete GeminiService + google_generative_ai (A-044). 13. Architecture: split router.dart by feature; extract workflow logic from the 10 god screens; break the 3 dependency cycles; pick one home for models. 14. Wire riverpod_lint via custom_lint in CI (A-023); add comms/crm/interactions tests + top-12 repository tests (A-033/A-034); replace the inventory test with a grep-derived guard covering SSE slugs (A-032). 15. Static a11y pass (C-004), Mixpanel consent gate (C-005), English-in-ar cleanup (A-061), doc-drift sweep (C-006).
9. What the audit did NOT find (positives worth recording) β
- Zero S1s. No data-loss path, no crash-on-clean-path, no unauthenticated data exposure β three suspected exposure findings (network_* anon policies, registry_voters, valuation_requests anonymous insert) were empirically disproven against live RLS/grants.
- Taxonomy canonicalization (2026-06-10 migrations) is consistent between live DB and repo catalogs β no drift.
- The anti-masking CI pattern (report steps reading real outcomes) works everywhere except the one promote step.
- fromJson discipline near-uniform (0
DateTime.parsein repositories; tryParse everywhere); finance repo is insert-only with DB triggers owning state β conflict-free by construction. - The bidi/i18n architecture (isolate-wrapping in
t(), LTR-forced phone inputs) is sound; findings are gaps in coverage, not design.
10. Appendix β
Refuted claims (adversarial verification log):
- Valuation sequence duplicate race (DATA) β refuted: live
valuations_base_sequence_uniquepartial unique index rejects duplicates; 0 dupes in 4,419 rows. - Anonymous insert into valuation_requests unprotected (SEC) β refuted empirically: anon role lacks INSERT grant; anonymous-session path blocked by
is_anonymous=falsepolicy guard. - First frame gated on network for expired sessions (PERF) β refuted by resolved-package source:
setInitialSessiondoes no awaited network refresh. - e2e triple-build wasteful (CI) β refuted: integration_test files compile as separate entrypoints regardless; directory form wouldn't halve cost.
Notable downgrades: OTP outage β transient incident (self-quieted; remaining issue is alerting); 4 unknown edge functions β no demonstrated gap, verification blocker only; voice-notes N+1 β latent (table empty); keepAlive-caches-error β riverpod 3.0.3 auto-retry softens; CI cache claim β half-wrong (pub cache IS cached).
Orchestration stats: 20 agents (3 evidence + 10 finders + 5 verifiers + critic + reconciler), 775 tool calls in the workflow, ~2.4M subagent tokens, ~33 min wall-clock for the workflow. 83 claims β 78 confirmed/downgraded β 74 register rows after merging 4 cross-finder duplicates, +6 critic-minted. Sampling: critic judged extrapolation risk LOW after reading 3 unsampled modules end-to-end.
Known-open items out of scope: device QA checklist (REMAINING_WORK B.1/B.4/B.5), Kuwaiti-Arabic translation quality review (C.1 β needs native speaker), web-repo surfaces (React SPA, PDFs, edge-function source beyond the 10 fetched).
