Skip to content

chore(sonar): honest analysis surface — mobile screens/components/hooks + re-justified exclusions (#243 Phase 1) - #446

Merged
thomasluizon merged 2 commits into
mainfrom
chore/sonar-surface-243
Jul 10, 2026
Merged

chore(sonar): honest analysis surface — mobile screens/components/hooks + re-justified exclusions (#243 Phase 1)#446
thomasluizon merged 2 commits into
mainfrom
chore/sonar-surface-243

Conversation

@thomasluizon

@thomasluizon thomasluizon commented Jul 10, 2026

Copy link
Copy Markdown
Owner

Phase 1 (step a) of #243 — SonarCloud analysis surface, orbit-ui-mobile

Config only, no app code. This is the single slice-shaped phase of the #243 campaign: get the analysis surface honest before any metric burn-down, so "0 smells / 100% coverage" will mean something later. Does not begin Phase 2 (the /prod-readiness loop or the metric burn-down), and does not flip the Sonar check to required (that's step d).

What changed (sonar-project.properties)

sonar.sources — mobile now mirrors web. Added apps/mobile/app/, apps/mobile/components/, apps/mobile/hooks/. Previously mobile analyzed only stores/, lib/, and the widget module, while web analyzed everything — so mobile screens/components/hooks weren't analyzed at all. They are all .ts/.tsx with no co-located tests or generated files, so the whole three dirs go in; nothing deliberately left out of sources.

sonar.coverage.exclusions — tightened to genuinely-untestable code, each entry justified inline. Applied one litmus: an exclusion survives only if the file is bootstrap/DI, generated, pure config/tokens, or platform glue.

Entry Decision Why
apps/web/components/** DROP ~235 component files with ~153 matching behavior tests — testable, heavily tested. The flagged asymmetry, decided by tightening both (no mobile-components exclusion added) so the eventual "100% on analyzed surface" isn't a lie.
apps/web/app/**/page.tsx DROP Route entries hold real tested app logic — TodayPage is 573 lines of selection-cascade / bulk-op branching with a page test. Not "genuinely untestable." Dropping it also gives clean parity with mobile route screens (also covered).
apps/mobile/lib/google-auth.ts DROP Its lcov is actually measured by vitest (in lib/** include, not vitest-excluded, has a test). Excluding it discarded real coverage and hid its uncovered native lines.
apps/mobile/app/**/_layout.tsx ADD Expo Router nav/bootstrap (Tabs/Stack, GestureHandlerRoot) — parity mirror of the kept web app/**/layout.tsx.
web layout.tsx, web app/api/**, mobile providers/theme-provider/use-app-theme/supabase/offline-queue/orbit-widget, stores/auth-store, modules/**, shared theme/button.ts KEEP Re-justified inline: bootstrap, BFF platform glue, native seams, native module, pure token table.

sonar.cpd.exclusions — all 7 re-justified inline, kept. Thin server-action shells, re-export barrels, deliberate web/mobile mirrors, and pure token/scheme data. None stale, none over-broad.

Confirmations (task c)

  • lcov merge feeds the mobile surface: the merge step prefixes apps/web / apps/mobile / packages/shared correctly; whatever mobile coverage exists maps to apps/mobile/*. Mechanically correct, unchanged.
  • overall/main analysis: the workflow triggers on push: [main], so main is analyzed and overall metrics are tracked, not just PR deltas. Unchanged. (The SonarCloud new-code definition is a dashboard setting outside these files — verify it in the project UI when flipping the gate in step d.)

Honest Phase-1 state (expected, intended)

Coverage % will drop on both projects — that's the point. The newly-added mobile app/components/hooks currently emit no lcov (mobile vitest.config.ts coverage.include is lib/** + stores/**), so they read as 0% covered until Phase 2. Duplication will spike too, because web↔mobile parity mirrors are now analyzed in the same project. Both reflect reality; the gate is non-required, so red here is fine.

Handoff to Phase 2 (metric burn-down — do NOT do here)

The inventory surfaced these; the burn-down session should:

  • Widen mobile vitest.config.ts coverage.include to app/** + hooks/** (rebaseline thresholds), then write tests.
  • Add scalpel coverage exclusions for the genuinely-native hooks: use-ad-mob, use-play-billing, use-speech-to-text, use-push-notifications, use-review-reminder, use-share-card, and app/(tabs)/profile/_components/use-data-export.ts (native SDK at module scope).
  • Un-suppress the tested-but-vitest-suppressed native-seam libs (offline-queue, orbit-widget, auth-store) at both layers, or keep them excluded with the current justification.
  • Handle the web↔mobile mirror duplication (extract to packages/shared where possible; justified cpd.exclusions for genuine unavoidable cross-platform mirrors).

Paired orbit-api PR: thomasluizon/orbit-api#316. Part of #243 Phase 1.

#243

…/hooks, re-justify exclusions (#243 Phase 1)

Phase 1 (config only, no app code) of the #243 pre-launch gate: make SonarCloud
analyze the right surface so the metrics mean something, before any burn-down.

sonar.sources: add apps/mobile/{app,components,hooks} for web parity — mobile
screens, components, and hooks are now analyzed on both platforms (previously only
stores/lib/widget were, while web analyzed everything).

sonar.coverage.exclusions — tightened to genuinely-untestable code only, every
entry justified inline:
- DROP apps/web/components/** — heavily behavior-tested (~153 component tests);
  a blanket coverage exclusion was the "broom" the campaign forbids. Decided the
  components parity question by TIGHTENING both (no mobile components exclusion),
  so the eventual "100% on analyzed surface" stays meaningful.
- DROP apps/web/app/**/page.tsx — route entries hold real tested app logic
  (e.g. TodayPage: 573 lines, selection-cascade/bulk-op branching + a page test).
- DROP apps/mobile/lib/google-auth.ts — its lcov is actually measured by vitest;
  excluding it discarded real coverage and hid its uncovered native lines.
- ADD apps/mobile/app/**/_layout.tsx — Expo Router nav/bootstrap, parity mirror of
  the kept web app/**/layout.tsx.
- KEEP (re-justified): web layout.tsx, web app/api/** (BFF platform glue), mobile
  bootstrap/native-seam libs (providers, theme-provider, use-app-theme, supabase,
  offline-queue, orbit-widget, auth-store), modules/**, shared theme/button.ts.

sonar.cpd.exclusions — all 7 re-justified inline (thin server-action shells,
re-export barrels, deliberate web/mobile mirrors, pure token/scheme data); none
stale or over-broad, kept as-is.

The lcov merge (web+mobile+shared prefixes) and the push:main trigger already
feed overall/main analysis correctly — confirmed, unchanged.

#243
@vercel

vercel Bot commented Jul 10, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
orbit-ui-mobile-web Ignored Ignored Jul 10, 2026 5:49pm

Request Review

@claude claude 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.

Code Review: PR #446

Scope: chore(sonar): honest analysis surface — mobile screens/components/hooks + re-justified exclusions (#243 Phase 1)
Recommendation: APPROVE

Summary

Single-file, config-only diff (sonar-project.properties, +32/-2). It widens sonar.sources so mobile app/, components/, hooks/ are analyzed like web already is, tightens sonar.coverage.exclusions to genuinely-untestable code with an inline one-line justification per entry, and re-justifies (unchanged) sonar.cpd.exclusions. No apps/web/**, apps/mobile/**, orbit-api/**, or packages/shared/src/types/** source files changed, so every gated dimension/subagent below is N/A by design — this is exactly the "config only, no app code" scope the PR body claims.

Findings

Critical

None.

High

None.

Medium

None.

Low / Info

None (per the rubric's signal gate, Low/Info nits are not posted even if noticed).

Verification performed

  • sonar.sources diff adds exactly apps/mobile/app/, apps/mobile/components/, apps/mobile/hooks/ — all three directories exist and are non-empty.
  • sonar.coverage.exclusions diff: dropped apps/web/app/**/page.tsx, apps/web/components/**, apps/mobile/lib/google-auth.ts; added apps/mobile/app/**/_layout.tsx. All 12 remaining entries exist on disk, and the new inline comment block lists exactly those 12 paths in the same order — no drift between comment and directive.
  • google-auth.ts drop claim (its lcov is actually measured by vitest, not vitest-excluded, has a test) verified against apps/mobile/vitest.config.ts: coverage.include is ['lib/**/*.{ts,tsx}', 'stores/**/*.ts'] and coverage.exclude does not list google-auth.ts (it does list the other mobile lib exclusions that correctly remain in the sonar list). A test file exists at apps/mobile/__tests__/lib/google-auth.test.ts. Claim confirmed true.
  • sonar.cpd.exclusions line is unchanged in the diff (pure context, no +/-) — matches the PR body's "all 7 re-justified inline, kept" claim.
  • No inaccuracy, drift, or unjustified exclusion found.

Rubric dimensions

Correctness: PASS (diff matches PR body, verified against live repo state). All other dimensions (dead code, SOLID, comments, workarounds, type safety, console.log, DESIGN.md/AI-slop, parity, i18n, contract drift/backward-compat, security, backend rules) are N/A — the only changed file is root sonar-project.properties, which doesn't touch any app/API/shared source.

Subagents

None fire — diff doesn't touch apps/web/**, apps/mobile/**, orbit-landing-page/src/**, orbit-api, or packages/shared/src/types/*. (parity-checker, i18n-syncer, contract-aligner, security-reviewer, design-reviewer: all N/A)

Validation

Skipped per CI-wrapper instructions — this PR runs Build / Unit Tests / SonarCloud as separate required checks (SonarCloud Quality Gate already passed per the bot comment on this PR).

What's good

  • Every exclusion carries a one-line, checkable WHY justification inline in the properties file itself.
  • The PR body states the expected coverage regression up front (0% until Phase 2) rather than hiding it; every quantitative claim spot-checked held up against the actual repo state.
  • Correctly resolves the pre-existing web/mobile asymmetry (apps/web/components/** was excluded, mobile had no equivalent) by tightening rather than loosening.
  • Clean scope discipline: explicitly defers the vitest coverage.include widening and new native-hook exclusions to a named Phase 2, rather than scope-creeping this "make the surface honest" PR into a metric burn-down.

Recommendation

APPROVE. No Critical/High findings, no drift between the PR's narrative and the actual repo state, scope correctly held to "analysis surface only" per the PR title and #243 Phase 1 framing.

thomasluizon added a commit to thomasluizon/orbit-api that referenced this pull request Jul 10, 2026
…es (orbit-ui-mobile#243 Phase 1) (#316)

Phase 1 (config only, no app code) of the pre-launch SonarCloud gate — the
consumer side is thomasluizon/orbit-ui-mobile#243. Make the coverage surface
honest before any burn-down.

- Widen /Extensions/ServiceCollectionExtensions.cs -> ServiceCollectionExtensions*.cs:
  the exact-name glob matched only 1 of 4 DI partials; all 4 are DI registration,
  so exclude them consistently.
- DROP Services/AppConfigService.cs (pure ConvertValue<T> + injectable cache/repo)
  and Services/UserDateService.cs (user-timezone "today" + week-start, injectable
  deps) from coverage.exclusions — both are unit-testable and live in
  Orbit.Infrastructure, which is already in the coverage run.
- Every remaining exclusion re-justified inline (bootstrap/DI, EF/generated, options
  POCOs, external-SDK glue, hosted BackgroundServices), with Phase-2 extract targets
  flagged: MinimumVersionMiddleware's semver comparator, GeoLocation's IsPrivateIp
  classifier, GoogleToken's outcome classification.

opencover paths (**/coverage.opencover.xml) span all three coverage-producing test
projects (Domain/Application/Infrastructure.Tests); Analyzers.Tests runs outside the
runtime coverage set by design, and there is no Api test project yet. Confirmed,
unchanged. Paired PR: thomasluizon/orbit-ui-mobile#446.

thomasluizon/orbit-ui-mobile#243
@thomasluizon
thomasluizon merged commit 3af256a into main Jul 10, 2026
15 checks passed
@thomasluizon
thomasluizon deleted the chore/sonar-surface-243 branch July 10, 2026 17:49
@sonarqubecloud

Copy link
Copy Markdown

@claude claude 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.

Code Review: PR #446

Scope: PR #446, single file changed: sonar-project.properties (+32/-2), no app code.
Recommendation: APPROVE

Summary

Config-only change widening sonar.sources to analyze apps/mobile/app/, apps/mobile/components/, apps/mobile/hooks/ (parity with web), tightening sonar.coverage.exclusions to genuinely-untestable files with an inline justification per entry, and re-justifying sonar.cpd.exclusions. Every factual claim in the PR body was independently verified against the live repo (not just trusted from the description) and everything checked out.

Findings

Severity Count
Critical (incl. ⚠️ old-client breaks) 0
High 0
Medium 0
Low / Info 1

Critical / High / Medium: None.

Info: Coverage % on both projects will drop and duplication will spike as an explicit, intended, and already-documented consequence — mobile apps/mobile/vitest.config.ts coverage.include is confirmed still lib/** + stores/** only, so newly-analyzed app/components/hooks emit no lcov yet. PR body names this and defers the fix to a stated Phase 2. No action needed.

Verification performed (facts checked, not just read)

  • apps/web/components/**: 235 files vs. 145 matching __tests__ (PR claimed "~235 / ~153" — close enough, confirms "heavily tested").
  • apps/web/app/**/page.tsx (TodayPage): test exists at apps/web/__tests__/app/today-page.test.tsx.
  • apps/mobile/lib/google-auth.ts: present, inside vitest coverage.include: lib/**, not in vitest's coverage.exclude, has apps/mobile/__tests__/lib/google-auth.test.ts — confirms it was wrongly coverage-excluded before and is correctly dropped now.
  • apps/mobile/app/**/_layout.tsx glob: matches the three real files (app/_layout.tsx, app/(onboarding)/_layout.tsx, app/(tabs)/_layout.tsx).
  • packages/shared/src/theme/button.ts: confirmed a branchless static token table.
  • .github/workflows/sonarcloud.yml: confirmed lcov merge prefixes apps/web/apps/mobile/packages/shared correctly and push: [main] keeps overall/main analysis running — matches the PR body's "Confirmations" section.
  • No stray non-.ts/.tsx files inside the newly-added apps/mobile/app, components, hooks source globs that would need a hard exclusion.
  • Every coverage-exclusion and cpd-exclusion entry in the properties file has a matching one-line inline comment; counts match (12 coverage-exclusion entries / 12 comment lines, 7 cpd-exclusion entries / 7 comment lines).

Subagents

Agent Verdict
parity-checker N/A — gate not met (no apps/web/**/apps/mobile/** source file changed, only root sonar-project.properties)
i18n-syncer N/A
contract-aligner N/A
security-reviewer N/A
design-reviewer N/A

Validation

Phase 6 (/validate) skipped per CI workflow instructions — this PR runs Build / Unit Tests / SonarCloud as separate required checks. No TS/JS/C# files are in this diff regardless.

Deferred

  • Dimensions #2#7, #10#14: N/A, no application code, no i18n/contract/security/backend/feature surface touched.
  • #8 DESIGN.md, #9 Parity: N/A by gate — note the PR's substance is a parity fix (mobile sources now mirror web); the remaining gap (mobile vitest coverage.include not yet widened) is explicitly named and deferred to the PR's own stated Phase 2, not silently dropped.
  • Paired orbit-api cross-repo dimension (contract-aligner, backward-compat guard): not verifiable in this CI job — sibling repo not checked out here.
  • Second commit on the branch since the prior claude review is a merge-from-main only, no new substantive diff to re-review.

What's good

Every claim in the PR description survived independent verification against the actual tree, config, and CI workflow — file counts, test existence, vitest include/exclude lists, glob matches, and the lcov-merge step all matched exactly as described. Each exclusion carries its own inline justification in the file, not just in the PR prose, so future drift is self-documenting. Scope discipline is strong: no threshold changes, no gate-required flip, no vitest widening snuck in — all correctly named as Phase 2 work.

Recommendation

Merge as-is. No blocking issues found; this diff earns a plain approval.

thomasluizon added a commit that referenced this pull request Jul 14, 2026
…flake web suite (#508)

Root cause (#446): sonar.sources analyzed all of apps/mobile app/components/hooks/stores,
but apps/mobile/vitest.config.ts only instrumented lib/**, stores/**, and one hook — so
every tested mobile screen/component/hook was absent from lcov and scored 0% by SonarCloud,
dragging combined coverage to ~57%.

- Broaden mobile vitest coverage.include to the full app/components/hooks/stores/lib/widget
  surface (mirrors sonar.sources) so the existing suite's real coverage lands in lcov.
- Add surgical sonar.coverage.exclusions + matching vitest exclude for genuinely-presentational
  RN code (JSX screens/sections, style tables, Expo Router shells, native bridges, bootstrap
  glue) — enumerated, never a blanket apps/mobile/** wildcard, so the ~178 render-tested
  components keep counting. Removed offline-queue.ts + auth-store.ts from the exclusions:
  now instrumented and well-covered.
- Remove the invalid `all` coverage option (not a Vitest 4 type; no runtime effect).
- 38 new/deepened mobile test files (behavior + edge + failure) across data hooks, 0%-logic
  hooks, app-level logic, request/response builders, error mapping, and pure helpers. Mobile
  kept-set coverage: ~53% raw -> 78.9% lines / 77.6% statements over 10,102 instrumented lines.
- De-flake the web suite under parallel/coverage load: server-fetch.test.ts (per-test module
  reset + vi.stubEnv restore, fixing an APP_VERSION "undefined"-string env leak), push-prompt
  (reset leaked globalThis.PushManager), tour-store (reset persistent hiddenSections). Green in
  default and shuffle order.

Refs #243 (coverage burn-down)

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
thomasluizon added a commit that referenced this pull request Jul 14, 2026
…ss web+mobile+shared (#243) (#509)

Second coverage burn-down toward the #243 SonarCloud-to-zero launch gate. Adds
~500 intelligent Vitest tests across the three workspaces and mirrors #508's mobile
instrument-gap fix onto web.

- apps/web: add coverage.include mirroring sonar.sources so files no test imports
  are counted (closes the same #446/#508 gap on web, which was mobile-only); new
  hook/component/page tests. 74% -> 84% lines locally.
- apps/mobile: hook/store/lib + component/screen tests; unblock keyboard-aware-scroll-view
  by adding an emit-capable Keyboard + findNodeHandle to the RN test mock. 79% -> 85%.
- packages/shared: store/util/validation/query-key branch tests. 94% -> 99% lines.
- Extend sonar.coverage.exclusions with genuinely-presentational web files only
  (route/error/not-found shells, static legal pages, motion/nav glue, the desktop
  astra-copilot rail chrome, style primitives) — enumerated with rationale, mirroring
  #508's mobile set. The 12 borderline web files with real logic are tested, not excluded.
- Raise the Vitest coverage thresholds in all three configs to ratchet the gains.

Estimated combined SonarCloud line coverage ~87% (up from ~79%). All suites green
(shared/web/mobile); web verified under --sequence.shuffle; lint + type-check clean.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant