Skip to content

refactor(api): clear residual duplication to 0% (#243) - #406

Merged
thomasluizon merged 1 commit into
mainfrom
chore/api-dedup-residual-zero
Jul 14, 2026
Merged

refactor(api): clear residual duplication to 0% (#243)#406
thomasluizon merged 1 commit into
mainfrom
chore/api-dedup-residual-zero

Conversation

@thomasluizon

Copy link
Copy Markdown
Owner

What & why

Drives orbit-api SonarCloud duplicated_lines_density from 0.1% → 0.0% (the last ~54 duplicated lines), satisfying #243's "Duplicated code → 0%". #404 deferred these files to avoid a concurrent-edit conflict; they are now free.

Each block was verified against SonarCloud's authoritative api/duplications/show before touching it, and handled per the honest extract-vs-exclude rule.

Real extractions (genuinely-shared logic)

HabitScheduleService self-duplication (~24 lines). IsHabitDueOnDate and IsHabitHistoricallyDueOnDate had an identical 12-line tail (active-days filter + frequency-unit switch). Extracted into one private MatchesFrequency(habit, target, anchor, unit, qty) helper, called from both. The methods still differ in their own earliest-date gate; only the shared tail is de-duped.

Level-sync idiom (6 copies → 1 helper). The GetLevelForXp + SetLevel "recompute level after awarding XP" block was copy-pasted in 6 places: both accept commands, SendCheerCommand, ChallengeProgressService, JoinChallengeCommand, and GamificationService.UpdateLevel. Unified into one canonical LevelDefinitions.SyncLevel(User) (co-located with GetLevelForXp); the now-redundant private UpdateLevel is deleted. Well past the third-use bar — real DRY, not metric-gaming.

Justified exclusion (irreducible parallel mirror)

AcceptAccountabilityPairCommand ↔ AcceptFriendRequestCommand. After the shared level-sync tail is extracted, the only residual is the BuildRequesterNotification parallel mirror: a null-guard + isPortuguese ternary skeleton that emits distinct localized copy for two independent accept events (accountability invite vs friend request) in two separate bounded contexts. CPD normalizes the differing string literals so the skeletons match; a shared builder would couple Accountability↔Social and leave CPD-flagged per-event title/body ternaries at each call site without improving readability. Added to sonar.cpd.exclusions with a documented rationale, consistent with the existing #404 exclusions (which are reserved for irreducible mirrors where the shared logic is already extracted).

Before / after

Metric Before After (expected)
duplicated_lines_density 0.1% ~0.0%

Verification (all foreground)

  • dotnet build Orbit.slnx0 errors
  • dotnet test Orbit.slnx6048 passed, 0 failed
  • dotnet ef migrations has-pending-model-changesfalse ("No changes have been made to the model")
  • src/Orbit.Api/openapi.jsonunchanged
  • No bare // narration in the diff (ORBIT0001-safe)

Behavior-preserving throughout — every change is a pure extraction or a config-level exclusion.

Refs thomasluizon/orbit-ui-mobile#243 (duplication → 0)

Drives orbit-api SonarCloud duplicated_lines_density 0.1% -> 0.0% (#404
deferred these files to avoid a concurrent-edit conflict).

Real extractions (genuinely-shared logic):
- HabitScheduleService: the identical active-days filter + frequency-unit
  switch tail of IsHabitDueOnDate and IsHabitHistoricallyDueOnDate is
  extracted into one private MatchesFrequency helper (self-dup ~24 lines).
- LevelDefinitions.SyncLevel(User): the GetLevelForXp + SetLevel level-sync
  idiom, previously copy-pasted in 6 places (both accept commands, SendCheer,
  ChallengeProgressService, JoinChallenge, and GamificationService.UpdateLevel),
  is unified into one canonical helper; UpdateLevel is deleted.

Justified exclusion (irreducible parallel mirror):
- AcceptAccountabilityPairCommand / AcceptFriendRequestCommand: after the
  shared level-sync is extracted, the only residual is the
  BuildRequesterNotification parallel mirror -- a null-guard + isPortuguese
  ternary skeleton emitting DISTINCT localized copy for two independent accept
  events in separate bounded contexts. CPD normalizes the differing string
  literals so the skeletons match; a shared builder would couple the two
  contexts without improving readability. Added to sonar.cpd.exclusions with
  rationale, consistent with the existing #404 exclusions.

Behavior-preserving: build 0 errors, all tests green, no EF model changes,
openapi.json unchanged.

Refs thomasluizon/orbit-ui-mobile#243 (duplication -> 0)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@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.

PR Review: #406 — refactor(api): clear residual duplication to 0% (#243)

Recommendation: APPROVE

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

What was reviewed

A pure, behavior-preserving DRY refactor across 9 files:

  • src/Orbit.Application/Habits/Services/HabitScheduleService.cs — extracts the identical active-days + frequency-unit tail shared by IsHabitDueOnDate/IsHabitHistoricallyDueOnDate into a private MatchesFrequency helper.
  • src/Orbit.Application/Gamification/LevelDefinitions.cs + 6 call sites (AcceptAccountabilityPairCommand.cs, JoinChallengeCommand.cs, ChallengeProgressService.cs, GamificationService.cs x4, AcceptFriendRequestCommand.cs, SendCheerCommand.cs) — unifies the copy-pasted "recompute level after XP" block into LevelDefinitions.SyncLevel(User), deletes the now-redundant private GamificationService.UpdateLevel.
  • .github/workflows/sonarcloud.yml — adds a documented sonar.cpd.exclusions entry for the one irreducible residual (BuildRequesterNotification in the accountability/friend-request accept commands — same skeleton, genuinely distinct localized copy).

Verification performed

  • Diffed every extraction byte-for-byte against the pre-diff inline code — confirmed identical logic, no altered condition.
  • Verified all 6 LevelDefinitions.SyncLevel call sites operate on the correct user/sender reference (no cross-user XP/level bleed) — cross-checked independently by the security-reviewer subagent (verdict: PASS).
  • contract-aligner correctly gated N/A — no DTO/Controller/packages/shared surface touched.
  • Repo-wide grep confirmed zero remaining references to deleted UpdateLevel and zero test references to the refactored private symbols — no test breakage from the code motion.
  • Read the actual BuildRequesterNotification bodies in both commands and confirmed the CPD-exclusion rationale in the PR body/workflow comment is accurate, not metric-gamed.

Findings (Info only, no action required)

  1. Faithful Extract Method, well past the "third use" DRY bar (LevelDefinitions.cs:80-85, HabitScheduleService.cs:500-513).
  2. CPD exclusion is honestly justified (.github/workflows/sonarcloud.yml:94-100), not a workaround — verified against actual code.

Deferred (N/A dimensions)

DESIGN.md/AI-slop, Parity, i18n, Contract drift, FEATURES.md parity — all N/A, no frontend/contract/user-facing-feature surface in this diff. dotnet build/dotnet test skipped per CI-wrapper convention (Build / Unit Tests / SonarCloud run as separate required checks on this PR).

Subagents

Agent Verdict
security-reviewer PASS
contract-aligner N/A (no contract surface touched)

@thomasluizon
thomasluizon merged commit ed11e89 into main Jul 14, 2026
19 checks passed
@thomasluizon
thomasluizon deleted the chore/api-dedup-residual-zero branch July 14, 2026 17:41
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