# AI-Driven Development Compatibility Report

**Project:** qslaravel (Laravel 13 / PHP 8.3+)
**Generated:** 2026-03-09
**Last Updated:** 2026-08-21
**Assessed by:** Claude Code (claude-opus-5)

---

## Executive Summary

| Metric | Value |
|--------|-------|
| **Overall AI Compatibility Score** | **74 / 100** |
| **Letter Grade** | **C+** |
| **Previous Score** | **71 / 100 (C+)** — assessed 2026-08-07 |
| **Risk Level for AI-Assisted Development** | **Medium** |
| **Verdict** | **The auth god class is gone.** A focused 7-commit decomposition cut `BaseAuthService` from **1,465 → 234 lines** and its constructor from **33 dependencies → 5**, splitting it into four interface-backed services (`UserRegistrationService`, `AuthResponseService`, `AuthTrackingService`, `ProgramEnrollmentService`) plus a `VoucherGiftEmailBuilder` — introducing the **first interfaces this codebase has ever had (0 → 5)**, all bound in `AppServiceProvider`. In parallel, **model factories went 1 → 9**, closing the standing "single biggest testing gap", and **PHPStan dropped 16 errors → 4**, with **zero genuine defects remaining** — all four are stale-baseline bookkeeping. The suite is green at **2,522 passing** serially and under `--parallel` (75s). Offsetting this are two facts, one new and one a correction: **`vendor/bin/pint --test` fails with 436 style issues** (309 in `app/`) — a third quality gate nobody had measured — and **return-type coverage across `app/` is 73%, not the 100% claimed in the last three reports**. That old figure counted only the methods that already *had* return types. `app/Services` genuinely is 100%; **API controllers are 8%** and **query classes 49%**. Unchanged: **no CI/CD**, `ChapterService` **1,522** (now the largest file in `app/`), the **706-line** `getModuleAnalytics()`, and **43** flat root-level services. |

---

## Category Scores

| # | Category | Previous | Current | Weight | Weighted | Status |
|---|----------|----------|---------|--------|----------|--------|
| 1 | Code Structure & Organization | 76 | 81/100 | 15% | 12.15 | `BaseAuthService` decomposed; first 5 interfaces; files >1,100 lines 6 → 5 |
| 2 | Consistency & Patterns | 73 | 74/100 | 15% | 11.10 | Interface + DI pattern seeded; offset by 436 Pint violations (newly measured) |
| 3 | Type Safety & Contracts | 60 | 65/100 | 20% | 13.00 | PHPStan 16 → 4 errors (0 genuine); interfaces 0 → 5; `strict_types` 1 → 11; return-type figure corrected downward |
| 4 | Documentation & PHPDoc | 82 | 83/100 | 15% | 12.45 | Service class docblocks 43% → 49%; rest flat |
| 5 | Testing Infrastructure | 76 | 81/100 | 15% | 12.15 | Factories 1 → 9; +7 test files; 2,522 pass, 0 fail, parallel-safe |
| 6 | Method Complexity | 46 | 52/100 | 10% | 5.20 | `createNewUser()` 296 → 116; >100-line methods 40 → 39 (logic relocated, not deleted) |
| 7 | Navigability & Discoverability | 80 | 83/100 | 10% | 8.30 | Auth flow readable via 5 named contracts |
| | **TOTAL** | **71** | | **100%** | **74.35** | **+3.35** |

### Score Visualization

```
Structure & Org     ████████████████████████████████████████░░░░░░░░░░  81%  (was 76%) ↑
Consistency         █████████████████████████████████████░░░░░░░░░░░░░  74%  (was 73%) ↑
Type Safety         ████████████████████████████████░░░░░░░░░░░░░░░░░░  65%  (was 60%) ↑
Documentation       █████████████████████████████████████████░░░░░░░░░  83%  ← Strongest (was 82%) ↑
Testing             ████████████████████████████████████████░░░░░░░░░░  81%  (was 76%) ↑
Method Complexity   ██████████████████████████░░░░░░░░░░░░░░░░░░░░░░░░  52%  ← Biggest gap (was 46%) ↑
Navigability        █████████████████████████████████████████░░░░░░░░░  83%  (was 80%) ↑
```

### Refactoring Impact (2026-08-21)

The period since 2026-08-07 was **the single most structurally significant push in this report's history** — only 16 commits, but seven of them dismantled the codebase's oldest and highest-risk god class.

**`BaseAuthService` is decomposed.** Named as the top structural target in every report since March, it finally moved:

| | 2026-08-07 | 2026-08-21 |
|---|---|---|
| `BaseAuthService` lines | **1,465** | **234** (−84%) |
| Constructor dependencies | **~33** | **5** |
| Largest method | `createNewUser()` **296 lines** | `createNewUser()` delegates in **12** |
| Interfaces in codebase | **0** | **5** |

The class is now a thin base that delegates through interfaces — its 13 methods are all under ~20 lines. Logic moved to:

```
app/Services/Auth/
├── UserRegistrationService.php        851  (createNewUser split into 13 private phase methods)
├── AuthResponseService.php            244
├── ProgramEnrollmentService.php       166
├── AuthTrackingService.php            149
├── BaseAuthService.php                234  (was 1,465)
└── *Interface.php ×4                  188  (first contracts in the codebase)
app/Services/Voucher/
├── VoucherGiftEmailBuilder.php        167  (de-duplicated voucher email construction)
└── VoucherGiftEmailBuilderInterface.php 42
```

All five interfaces are bound to concrete classes in `AppServiceProvider::register()`, so AI can now discover an auth signature by reading a 27–68 line contract instead of a 1,465-line implementation.

**Model factories 1 → 9** — the gap flagged as "the single biggest testing gap" in three consecutive reports. `database/factories/` now holds `Admin`, `Coupon`, `Program`, `User`, `UserConfig`, `UserInfo`, `UserProgram`, `Voucher` plus an abstract `BaseFactory`. The `BaseFactory` docblock is exemplary AI-facing documentation: it explains *why* `newModel()` uses `forceFill()` (the app enables `preventSilentlyDiscardingAttributes()` and legacy `tbl_*` models omit their PK from `$fillable`), and documents the `bare()` state's one behavioural difference (`toArray()` includes nulled keys). A `tests/Unit/Database/FactoriesTest.php` (178 lines) locks the contract.

> **Important limitation, stated in `BaseFactory` itself:** these factories are **`make()`-only**. The core `tbl_*` tables have no CREATE migrations, so `create()` fails against the SQLite test connection. AI gets in-memory fixtures, not database seeding.

**PHPStan is effectively green.** `vendor/bin/phpstan analyse` fell from **16 errors → 4**, and — unlike last period — **none of the four are real defects**. All are `ignore.unmatched` / `ignore.count` entries left over because the underlying bugs were *fixed*: the `AcquisitionCronService:47` null-coalesce, the `UserActivityService` always-true comparison and its unreachable code, and a stale `@param` parse error. The baseline shrank **3,040 → 2,896 lines** (502 → **478** grandfathered entries). Every genuine error called out in the last report — the `LengthAwarePaginator` `pluck()`/`transform()` calls in `ResearchUsController` and `VoucherController`, the dead guards in `BaseAuthService` — is gone. **One `--generate-baseline` run makes this gate pass.**

**Test suite green and growing.** 181 → **188** files (Unit 90 → **96**, service unit tests 75 → **80**), **2,471 → 2,522 passing** / 10 skipped / 0 failed (8,682 assertions). Verified green both serially (115s) and under `--parallel` with 4 processes (75s). New unit tests cover every extracted auth service.

**`declare(strict_types=1)` 1 → 11 files** — all 11 in the new `Auth/` and `Voucher/` code. Runtime coercion is now off in the codebase's highest-risk domain.

**Regressed, unchanged, or newly discovered:**

- **`vendor/bin/pint --test` fails: 436 style issues across 799 files** — **309 in `app/`**, 93 in `tests/`. This gate has never appeared in this report. It matters directly: Recommendation 0.2 proposes CI running `pint --test`, and that CI would fail on day one. Violations are broad and mechanical (`concat_space`, `new_with_parentheses`, `trailing_comma_in_multiline`, `ordered_imports`, `fully_qualified_strict_types`) — the kind of drift that makes AI-generated code stylistically indistinguishable from noise in review.
- **Return-type coverage was never 100%.** See the correction below.
- **`ChapterService` 1,522 lines is now the largest file in `app/`** and the top remaining decomposition target.
- **`ModuleAnalyticsController::getModuleAnalytics()` is still 706 lines** — unchanged, still the largest method in the codebase.
- **Methods >100 lines: 40 → 39.** Re-measured with an identical script against both trees. `BaseAuthService::createNewUser()` (296) left the list, but `AuthResponseService::buildUserData()` (141) and `ProgramEnrollmentService::checkAndUpdateUserProgram()` (120) simply carried the same bodies to new homes. **Decomposition moved the long methods; it did not shorten them.**
- **43 flat root-level services** — unchanged. `app/Services/Voucher/` was added (9 domain namespaces now), but the ungrouped root pool did not shrink.
- **Loose comparisons 706 → 701** (−5) — essentially flat after last period's −84.
- **Form Requests hold at 66**, still **0 in `app/Http/Controllers/Api/`**. Inline validation holds at **6 call sites**, all in `NewYearEmailController`.
- **Still no CI/CD** — `.github/` does not exist.

> **Working-tree note (uncommitted at time of assessment):** `routes/api.php` adds an optional-OTP variant of `ResendEmailOTP` and comments out `POST User/Search`; `Api/UserController::resendEmailOTP()` drops its unused `Request $request` parameter. Neither affects the metrics above.

### Correction: return-type coverage is 73%, not 100%

The reports dated 2026-07-18 and 2026-08-07 both stated *"Return-type coverage across all of `app/` is 100%"*. **That is wrong, and it was wrong by construction:** the figures quoted (`331/331`, `1,510/1,510`, `100/100`) used the count of methods that *had* return types as both numerator and denominator. Any such ratio is 100%.

Re-measured with a token-based parser over every named non-constructor function:

| Layer | Return types (2026-08-07) | Return types (2026-08-21) |
|-------|---------------------------|---------------------------|
| `app/Services` | 659/659 (**100%**) | 706/706 (**100%**) |
| `app/Http/Requests` | 123/123 (**100%**) | 123/123 (**100%**) |
| `app/Enums` | 11/11 (**100%**) | 11/11 (**100%**) |
| `app/Http/Controllers` (all) | 233/429 (54%) | 227/355 (**64%**) |
| `app/Models` | 59/93 (63%) | 59/93 (**63%**) |
| `app/Http/Queries` | 331/673 (49%) | 332/673 (**49%**) |
| `app/Http/Middleware` | 5/11 (45%) | 5/11 (**45%**) |
| **`app/Http/Controllers/Api`** | **6/72 (8%)** | **6/72 (8%)** |
| **All of `app/`** | **1,507/2,076 (73%)** | **1,549/2,117 (73%)** |

The March 2026 "add return types to all service methods" work **did** land and **has** held — `app/Services` is genuinely 100%. It just never reached the query, controller, model, or middleware layers, and the reporting hid that. `app/Http/Controllers/Api` at **6 of 72** is the starkest gap: `CLAUDE.md` names `UserController` a reference example of the required style, yet not one of its six methods declares a return type.

This is a measurement fix, not a code regression. It does mean the previously published Type Safety scores of 61 and 60 rested on an inflated input.

### Refactoring Impact (2026-08-07)

The period since 2026-07-18 was a **breadth sweep over the admin controller/query surface** — 50 commits touching 171 files.

- **Test suite grew 160 → 181 files** (+13%): Feature 73 → **89**, Unit 85 → **90**, service unit tests 71 → **75**. New coverage landed on `FunnelController`, `UserFunnelController`, `DashboardController`, `ModuleAnalyticsController`, `MarketingV2Controller`, `CampaignController`, `FBMatchingController`, `ResearchUsController`, and the post-quit/tracker-content stack.
- **Suite went green — and the Mockery redeclaration bug was fixed.** 2,471 passed / 10 skipped / 0 failed, serially and under `--parallel`. Delivered Recommendation **2.5**.
- **PHPDoc breadth push.** Method-level docblock coverage reached **94%** on query classes, **93%** on API controllers, **90%** on web controllers, **72%** on services. Model `@property` coverage held at **97%**.
- **Form Requests 58 → 66**, referenced by **35 web controllers**. Inline `$request->validate()` / `Validator::make` down to **6 call sites**.
- **Loose comparisons 790 → 706** (−84).
- **New supporting infrastructure**: `app/Rules/` (2), `app/Clients/UserApiClient`, `app/Cache/RaceSafeFilesystem`, `app/Exceptions/ImageAlreadyExistsException`, `app/Support/DeepLinkPlatform`, 2 new middleware.
- **Regressed:** PHPStan failed with 16 errors (~10 genuine, on freshly-touched files); `BaseAuthService` grew 1,459 → 1,465; flat root services 40 → 43.

### Refactoring Impact (2026-07-18)

Dominated by a single push: **raising static analysis from PHPStan level 1 to level 5**, with **larastan** wired in and a 3,064-line baseline grandfathering existing violations so the gate applies to new and changed code. Delivered Recommendation **2.4**.

**Not touched:** `BaseAuthService` 1,459, `UserQuery` 1,180, `declare(strict_types=1)` 1 file, 0 interfaces, 1 model factory, no CI/CD.

### Refactoring Impact (2026-07-10)

Dominated by **admin-wide Form Request validation**: 3 → 55 concrete classes under `app/Http/Requests/Admin/`, wired into 24 controllers, replacing inline `$request->validate()` blocks. Delivered Recommendation **2.1** for the admin write surface.

### Refactoring Impact (2026-06-30)

- **FirebaseBusinessService decomposed** — 2,619 lines → a **228-line facade** over 8 domain campaign services, plus notification infrastructure. All 36 public `run*` signatures preserved.
- **Marketing layer split** — `MarketingEmailService` → **125 lines**; logic under `app/Services/Marketing/`.
- **Cron layer split** — `CronService` → **194 lines**; domain services under `app/Services/Cron/`.
- **Test suite nearly doubled** — 83 → 154 files.
- **Registry pattern** — `FirebaseCampaignRegistry`, `MarketingCampaignRegistry`, `CronJobRegistry`.

---

## Codebase Overview

| Metric | Previous (2026-08-07) | Current (2026-08-21) |
|--------|----------|---------|
| Total PHP Files (app/) | 508 | **518** (+10) |
| Models | 94 | **94** |
| Controllers | 77 (15 API + 62 Web) | **77** (15 API + 62 Web) |
| Services | 108 | **118** (+10) |
| — of which flat at `app/Services/` root | 43 | **43** (unchanged) |
| — domain sub-namespaces | 8 | **9** (+`Voucher/`) |
| Query Classes | 93 | **93** |
| Test Files | 181 | **188** (+7) |
| Passing Tests | 2,471 pass / 10 skip / 0 fail | **2,522 pass / 10 skip / 0 fail** (8,682 assertions) |
| Suite runtime | ~71s parallel | 115s serial / **75s parallel** (4 procs) |
| Form Requests | 66 | **66** (56 admin + 10 root) |
| **PHPStan** | **5 / 9 — FAILS, 16 errors** | **5 / 9 — 4 errors, all baseline drift, 0 genuine** |
| PHPStan baseline | 3,040 lines / 502 entries | **2,896 lines / 478 entries** |
| **Pint (`--test`)** | not measured | **FAILS — 436 issues / 799 files** (309 in `app/`) |
| Middleware | 10 | **10** |
| Enums | 4 | **4** |
| Traits | 6 | **6** |
| Helpers | 6 | 6 |
| Console Commands | 14 | **14** |
| **Model Factories** | **1** (User only) | **9** (8 models + `BaseFactory`) |
| Models with `HasFactory` | — | **24** (8 have a factory) |
| `declare(strict_types=1)` files | 1 | **11** |
| **Interfaces / Contracts** | **0** | **5** |
| CI/CD pipeline | None | **None** |
| Loose comparisons (`==` / `!=`) | 706 | **701** (−5) |
| Methods > 100 lines | 40 (re-measured) | **39** |
| Files > 1,100 lines | 6 | **5** |
| Return-type coverage (`app/`) | 73% (corrected) | **73%** |
| API routes (`routes/api.php`) | 95 (over-counted) | **78** |
| Third-Party Integrations | 10 | 10 |
| Database Connections | 4 | 4 |

### Measured Coverage Snapshot (2026-08-21)

| Layer | Class-level docblocks | Method-level docblocks | Return types (non-ctor) |
|-------|----------------------|------------------------|-------------------------|
| `app/Models` | **91/94 (97%)** | 12/93 (13%) | 59/93 (63%) |
| `app/Http/Queries` | 23/93 (25%) | **638/678 (94%)** | 332/673 (49%) |
| `app/Http/Controllers/Api` | 1/15 (7%) | **80/86 (93%)** | **6/72 (8%)** |
| `app/Http/Controllers` (all) | 28/77 (36%) | **379/423 (90%)** | 227/355 (64%) |
| `app/Services` | **58/118 (49%)** ↑ | 578/794 (73%) | **706/706 (100%)** |
| `app/Http/Requests` | 18/66 (27%) | 42/123 (34%) | **123/123 (100%)** |
| `app/Http/Middleware` | 1/10 (10%) | 7/13 (54%) | 5/11 (45%) |
| `app/Enums` | 0/4 (0%) | 8/11 (73%) | **11/11 (100%)** |

Service class-level docblocks rose **43% → 49%** because all twelve new `Auth/` and `Voucher/` classes ship with one. Model *method* docblocks at **13%** are a newly surfaced gap — models are well annotated with `@property` but their relation/scope/accessor methods are not.

### Service Organization (2026-08-21)

```
app/Services/
├── Auth/           12 files  (Base, Email, Social, SSO + 4 extracted services + 4 interfaces)
├── Marketing/      19 files
├── Firebase/       18 files
├── Cron/           13 files
├── User/            7 files
├── Subscription/    2 files
├── Voucher/         2 files  <- new this period
├── Apple/           1 file
├── Google/          1 file
└── 43 root-level service files (still flat)
```

---

## Category 1: Code Structure & Organization (81/100, was 76)

### Resolved This Period

**The auth god class is decomposed.** `BaseAuthService` went 1,465 → 234 lines and 33 → 5 constructor dependencies. Registration, response formatting, journey tracking, and program enrollment each became their own service behind an interface. This was Recommendation **3.1**'s headline target across five consecutive reports.

**Interfaces exist for the first time.** Five contracts (`UserRegistrationServiceInterface`, `AuthResponseServiceInterface`, `AuthTrackingServiceInterface`, `ProgramEnrollmentServiceInterface`, `VoucherGiftEmailBuilderInterface`), all bound in `AppServiceProvider`. The 27–68 line contracts are now the fastest way for AI to learn an auth signature. This partially delivers a Priority 4 item.

**Files over 1,100 lines: 6 → 5.**

### What Still Works Well

**Domain decomposition remains strong.** `Firebase/Campaigns/`, `Marketing/`, `Cron/`, and now `Auth/` and `Voucher/` give AI small, single-purpose targets discoverable by path.

**God classes behind facades.** `FirebaseBusinessService` (228-line facade), `MarketingEmailService` (125), `CronService` (194), and now `BaseAuthService` (234) all follow the same shape.

**Form Requests pervasive on the admin surface.** 56 classes under `app/Http/Requests/Admin/` across 25 controllers.

**Registry pattern for dispatch.** `FirebaseCampaignRegistry`, `MarketingCampaignRegistry`, `CronJobRegistry`.

### What Hurts AI Comprehension

**`UserRegistrationService` is 851 lines** — the decomposition produced one large child. It is far better structured than what it replaced (13 named private phase methods, longest 116 lines), but it is still a file AI must read in bulk to change signup.

**`ChapterService` (1,522) is now the largest file in `app/`** and has inherited the "top structural target" title.

**43 services still flat at `app/Services/` root** — unchanged for two periods. Notification, commerce, integration, search, and core concerns remain mixed.

**93 query classes still under `app/Http/Queries/`** despite having nothing to do with HTTP.

**`ModuleAnalyticsController::getModuleAnalytics()` is still 706 lines** — 93% of its 757-line controller.

---

## Category 2: Consistency & Patterns (74/100, was 73)

### New This Period

**Interface-backed constructor injection is now a demonstrated pattern.** `AppServiceProvider::register()` binds five interfaces to concrete classes; `BaseAuthService` type-hints the contracts, not the implementations. This is the first copyable example of dependency inversion in the codebase — but it exists in exactly one domain, so it is a seed, not yet a convention.

### Newly Measured — and Red

**`vendor/bin/pint --test` reports 436 style issues across 799 files** (309 in `app/`, 93 in `tests/`, the rest in `config/`, `database/`, `routes/`).

| Common violations | Where |
|---|---|
| `concat_space`, `single_quote`, `binary_operator_spaces` | throughout `app/` and `tests/` |
| `new_with_parentheses`, `trailing_comma_in_multiline` | heavily in `tests/Unit/Services/` |
| `ordered_imports`, `fully_qualified_strict_types` | service + test files |
| `no_superfluous_phpdoc_tags`, `class_attributes_separation` | traits, `UserProfileService` |

`CLAUDE.md` documents `vendor/bin/pint` as the formatter, and Recommendation 0.2 proposes CI running `pint --test` — that CI would fail immediately. Formatting drift is low-severity per instance, but at 436 instances it means AI-generated code cannot be distinguished from existing code by style, and a future `pint` run would produce an unreviewable whole-repo diff.

### Still Inconsistent

The **API surface remains bespoke**. API controllers use *neither* Form Requests *nor* `validate()`: input arrives through `BaseApiController::getPostData()` and is checked ad hoc inside services. They also carry **6 return types across 72 methods**. An AI adding an API endpoint has no declarative input contract and no typed signature to copy — this is the largest remaining consistency gap and the reason Recommendation 2.1 stays open.

**Inline validation holds at 6 call sites**, all `\Validator::make` in `NewYearEmailController` (lines 37, 124, 212, 298, 384, 470) — one file away from zero.

### Previously Resolved (retained)

- Form Request validation adopted admin-wide (3 → 55 → 66 classes). **DONE for admin** (2026-07-10).
- `FirebaseBusinessService` 40+ near-identical methods eliminated; stale-`microtime` worker bug fixed. **DONE** (2026-06-30).
- Registry + facade patterns standardized across Firebase, Marketing, Cron. **DONE** (2026-06-30).
- `userJournyLog()` → `userJourneyLog()` typo fixed (2026-03-13).
- `Platform::fromString()` replaces magic strings (2026-03-13).
- `validateUserIdMatch()` consolidates ~50 copy-pasted blocks (2026-03-13).
- `SourceDataService` constructor DI in `BaseAuthService` (2026-03-26).
- `CalculatesUtcOffset` trait extracts shared UTC logic (2026-03-26).

### Remaining Naming Inconsistencies

| Pattern | Example | Location |
|---------|---------|----------|
| PascalCase method | `LanguageList()` | `ProgramService.php` |
| PascalCase controller action | `GetUserProgramProgressByDayID()` | `Api/ChapterController.php` |
| Typo in public method | `upadateChapterStatus()` | `Api/ChapterController.php` |
| Lowercase compound | `activatevoucher()` | `VoucherService.php` |
| Numeric suffix | `getUsersList3()` | `UserQuery.php` |
| Mixed route naming | `SocialLogin` vs `getSubDetails` | `routes/api.php` |

### Error Handling Patterns

| Layer | Pattern | Consistency |
|-------|---------|-------------|
| **Services** | 5 competing patterns (try-catch, inline, early return, rollback, none) | **Inconsistent** |
| **Controllers** | Mixed delegation and inline handling; `ApiResponse` trait used by **13 of 77** | **Inconsistent** |

---

## Category 3: Type Safety & Contracts (65/100, was 60)

### Key Metrics

| Metric | Previous | Current | Impact |
|--------|----------|---------|--------|
| **PHPStan level** | **5 / 9** | **5 / 9** | Held |
| **PHPStan run status** | **FAILS — 16 errors, ~10 genuine** | **4 errors, 0 genuine** | **Gate is effectively green** |
| PHPStan baseline | 3,040 lines / 502 entries | **2,896 / 478** | −24 grandfathered violations |
| **Interface/contract files** | **0** | **5** | **First contracts in the codebase** |
| Files with `declare(strict_types=1)` | 1 of 508 | **11 of 518** | All in new `Auth/`+`Voucher/` code |
| Loose comparisons (`==` / `!=`) | 706 | **701** (−5) | Essentially flat |
| Return-type coverage (`app/`) | 73% (**corrected** from "100%") | **73%** (1,549/2,117) | Services 100%, API controllers 8% |
| Typed DTO / value objects | `EmailResult`, `SendResult`, `CouponDecision`, `MarketingCampaignConfig`, `HourlyDateRange`, `DeepLinkPlatform` | same | Unchanged |
| Enum files | 4 | **4** | Unchanged |
| Form Request classes | 66 | **66** | Unchanged |

### What Improved

**The gate is essentially green.** Every genuine error named in the last report has been fixed:

| Error from 2026-08-07 | Status |
|---|---|
| `ResearchUsController:56` — `pluck()` on `LengthAwarePaginator` contract | **Fixed** |
| `VoucherController:87,141,186` — `transform()` on the contract | **Fixed** |
| `UserActivityService:450-453` — always-true `!==` → unreachable code | **Fixed** (live logic bug) |
| `BaseAuthService:717,895` — dead `isset()`/`empty()` guards | **Fixed** (class rewritten) |
| `AcquisitionCronService:47` — `??` on non-nullable | **Fixed** |

The 4 remaining errors are all `ignore.unmatched` / `ignore.count` entries in `phpstan-baseline.neon` describing violations that no longer exist. They are bookkeeping, cleared by one `--generate-baseline` run.

**Interfaces exist.** Five contracts with full PHPDoc, bound in the container. This is the first time AI can read a signature without reading an implementation.

**`strict_types` 1 → 11.** Runtime coercion is now disabled across the entire new auth surface — the highest-risk domain in the app.

### What Still Needs Work

- **`app/Http/Controllers/Api` declares 6 return types across 72 methods (8%).** `CLAUDE.md` mandates a native return type on every method and cites `UserController` as a reference example; that file has 0 of 6. This is the single cheapest type-safety win available.
- **`app/Http/Queries` is at 49%** (332/673) — 341 untyped query methods feeding the data layer.
- **`app/Models` 63%**, **`app/Http/Middleware` 45%**.
- **`declare(strict_types=1)` in 11 of 518 files (2%).**
- **Only 5 interfaces**, all in `Auth/`+`Voucher/`. The other 113 services are still concrete-only.
- Hungarian notation still obscures intent in DB columns (`iUserID`, `vEmail`, `bActive`).
- **API** input is neither Form-Request-validated nor `validate()`-checked — it flows through `getPostData()` untyped.

---

## Category 4: Documentation & PHPDoc (83/100, was 82)

### Coverage by Layer (measured 2026-08-21)

| Layer | Class-level | Method-level | Notes |
|-------|-------------|--------------|-------|
| Models | **91/94 (97%)** | 12/93 (13%) | `@property` strong; relation/scope methods undocumented |
| Query Classes | 23/93 (25%) | **638/678 (94%)** | Held from last period |
| API Controllers | 1/15 (7%) | **80/86 (93%)** | Methods documented; classes lack headers |
| Web/Admin Controllers | 28/77 (36%) | **379/423 (90%)** | Held |
| Services | **58/118 (49%)** ↑ | **578/794 (73%)** ↑ | +12 fully documented auth/voucher classes |
| Form Requests | 18/66 (27%) | 42/123 (34%) | Rules self-documenting; headers thin |
| Middleware | 1/10 (10%) | 7/13 (54%) | Near-zero class headers |
| Enums | 0/4 (0%) | 8/11 (73%) | Zero class headers |

### Why the Gain

Every class added this period — 4 auth services, 4 auth interfaces, `VoucherGiftEmailBuilder` + interface, and the factory tree — ships with a class-level docblock. Service class coverage rose 43% → **49%**.

**`database/factories/BaseFactory.php` is the strongest single piece of AI-facing documentation in the repo.** It does not just describe what the class does; it explains *why* (`preventSilentlyDiscardingAttributes()` + `$fillable` omitting PKs), states the `make()`-only constraint and its cause (no CREATE migrations for `tbl_*`), and warns precisely when `bare()` will mislead you (`toArray()` includes nulled keys — use `(new Model)->forceFill([...])` if the subject serialises). That is the shape every class header in this codebase should aspire to.

### What's Still Missing

- **Class-level docblocks** remain the standing gap: services 49%, controllers 36%, API controllers 7%, Form Requests 27%, middleware 10%, **enums 0%**. `CLAUDE.md` requires one on every class.
- **Model method PHPDoc at 13%** — newly surfaced. 81 undocumented relation/scope/accessor methods across 94 models.
- **Service method PHPDoc at 73%** — ~216 undocumented methods, concentrated in the extracted campaign/processor classes.

### CLAUDE.md Provides Strong Project Context

`CLAUDE.md` remains a major asset — architecture, patterns, commands, integrations. Two of its stated rules are, however, materially unmet in the code it points to: the "every method declares a native return type" rule (73% overall, 8% in API controllers) and the "every class carries a PHPDoc block" rule (49% in services). The reference example it names, `Api/UserController`, satisfies neither.

---

## Category 5: Testing Infrastructure (81/100, was 76)

### Test Distribution

| Category | Previous | Current | Notes |
|----------|----------|---------|-------|
| Total test files | 181 | **188** | +7 |
| Feature Tests | 89 | **89** | Unchanged |
| Unit Tests | 90 | **96** | +6 — all extracted auth services |
| Service unit tests | 75 | **80** | +5 |
| **Suite result** | 2,471 pass / 10 skip / 0 fail | **2,522 pass / 10 skip / 0 fail** | 8,682 assertions |
| Serial / parallel runtime | ~71s parallel | **115s serial / 75s parallel** (4 procs) | Both exit 0 |
| **Model Factories** | **1 (User)** | **9** (8 models + `BaseFactory`) | **Recommendation 2.3 substantially delivered** |
| Test files using `::factory()` | ~1 | **13** | Adoption still early |
| Static Analysis | PHPStan 5/9 — **FAILS (16)** | PHPStan 5/9 — **4 baseline-drift errors** | Effectively green |
| **Code style** | not measured | **Pint FAILS — 436 issues** | New red gate |
| CI/CD Pipeline | None | **None** | `.github/` does not exist |

### What Works

- **Model factories exist.** `Admin`, `Coupon`, `Program`, `User`, `UserConfig`, `UserInfo`, `UserProgram`, `Voucher` — the resources AI most often needs to fabricate. `tests/Unit/Database/FactoriesTest.php` locks their behaviour, and a documented `bare()` state lets a test build a model carrying only the attributes it explicitly sets.
- **The suite is green and parallel-safe**, verified both ways this assessment.
- **New auth services all have unit tests**: `AuthResponseServiceTest` (134), `AuthTrackingServiceTest` (240), `ProgramEnrollmentServiceTest` (250), `UserRegistrationServiceTest` (123), `VoucherGiftEmailBuilderTest` (139).
- **`tests/Unit/Services/` mirrors the service tree** — AI can locate the test for any service by path.
- **Modern Pest PHP** with BDD-style `describe()`/`it()` and AAA structure.

### What's Missing for AI

**Factories are `make()`-only and cover 8 of 94 models.** `create()` fails because the core `tbl_*` tables have no CREATE migrations — so there is still no way to build a persisted fixture graph, and any test needing real rows still hand-builds them. Adoption is early: **13 of 188 test files** call `::factory()`, and 24 models declare `HasFactory` while only 8 have one. The gap narrowed sharply; it did not close.

**No CI/CD pipeline.** Three gates now exist locally — `pest` (green), `phpstan` (4 bookkeeping errors), `pint --test` (**436 issues**) — and nothing runs any of them on push. Last period this cost the codebase ~10 shipped defects. **This remains the highest-leverage single day of work in this report**, with one new caveat: `pint` must be brought to green *before* it can be a gate, or CI will be red from its first run.

---

## Category 6: Method Complexity (52/100, was 46)

### God Classes — Status

| Class | Previous | Current | Status |
|-------|----------|---------|--------|
| `FirebaseBusinessService` | 2,619 lines | **228-line facade** | **Decomposed** ✅ |
| `MarketingEmailService` | large monolith | **125 lines** | **Decomposed** ✅ |
| `CronService` | monolith | **194 lines** | **Decomposed** ✅ |
| **`BaseAuthService`** | **1,465 lines, ~33 deps** | **234 lines, 5 deps** | **Decomposed** ✅ **(new)** |
| `ChapterService` | 1,522 lines | **1,522 lines** | **Now the largest file in `app/`** ⚠️ |
| `MarketingV2Query` | 1,418 | **1,418** | Unchanged ⚠️ |
| `UserProgramService` | 1,410 | **1,410** | Unchanged ⚠️ |
| `FirebaseNotificationQuery` | 1,261 | **1,261** | Unchanged ⚠️ |
| `UserQuery` | 1,180 | **1,180** | Unchanged ⚠️ |
| `CampaignQuery` | — | **895** | Next tier |
| `UserRegistrationService` | — | **851** | New — extracted from `BaseAuthService` ⚠️ |
| `ModuleAnalyticsController` | 757 | **757** | Unchanged, 3 methods ⚠️ |

### God Methods — 39 methods exceed 100 lines (was 40)

| Lines | Method | Change |
|-------|--------|--------|
| **706** | `ModuleAnalyticsController::getModuleAnalytics()` | unchanged — largest in codebase |
| 266 | `ProgramService::getProgramSubscriptionDetails()` | unchanged |
| 248 | `RazorpayListenerQuery::updateRazorpayData()` | unchanged |
| 238 | `FunnelController::getFunnelResult()` | unchanged |
| 216 | `StripeListenerQuery::updateStripeData()` | unchanged |
| 178 | `UserFunnelController::getUserFunnelResult()` / `FormViewService::formview()` | unchanged |
| 169 | `RazorpayListenerQuery::enrollSubscriberFromListener()` | unchanged |
| 160 | `NotificationsWorkerCommand::handle()` | unchanged |
| 149 / 147 | `CouponService::activateCoupon()` / `VoucherService::activatevoucher()` | unchanged |
| 146 | `ApiTimingController::processPayloadTiming()` | unchanged |
| 142 | `MarketingV2Controller::campaignStyleExcel()` | unchanged |
| **141** | **`AuthResponseService::buildUserData()`** | **was `BaseAuthService::getUserData()` (141) — relocated** |
| 141 | `ChapterService::updateChapterStatus()` | unchanged |
| **120** | **`ProgramEnrollmentService::checkAndUpdateUserProgram()`** | **was `BaseAuthService::checkAndUpdateUserProgram()` (120) — relocated** |
| — | ~~`BaseAuthService::createNewUser()` (296)~~ | **split into 13 phase methods; entry point now 116** |

### What Improved

- **`BaseAuthService::createNewUser()` 296 → 116 lines**, with 13 named private phase methods (`insertUserRecord`, `createUserInfoRecord`, `applyVouchersAndCampaign`, `finalizeUserProfileAndToken`, …). This is genuine decomposition, not relocation.
- **`BaseAuthService` itself has no method over ~20 lines.**
- **Files over 1,100 lines: 6 → 5.**

### What Regressed or Held

- **The >100-line census barely moved (40 → 39).** Two of the three long methods that left `BaseAuthService` reappeared verbatim in their new homes. Extracting a class is not the same as shortening its methods.
- **`ModuleAnalyticsController::getModuleAnalytics()` (706 lines) is untouched** and is now, by a wide margin, the worst artefact in the codebase.
- `UserRegistrationService` at 851 lines is a new large file — well-organized internally, but large.

### AI Impact

Modifying a Firebase campaign or an auth sub-service is now low-risk: isolated, interface-backed, unit-tested classes. Modifying `ChapterService` (1,522) or `getModuleAnalytics()` (706) remains high-risk.

**Failure probability for non-trivial `BaseAuthService` modifications: ~50-60% → ~25-30%.**

---

## Category 7: Navigability & Discoverability (83/100, was 80)

### Strengths

| Asset | Value to AI |
|-------|------------|
| **5 service interfaces** | **First discoverable contracts — read 27-68 lines instead of a 1,465-line class** |
| `CLAUDE.md` / `CLAUDE.local.md` | Excellent project + container context |
| `data-dictionary/` (121 files) | Auto-generated table/column docs for all 3 databases |
| **Domain-organized services (9 namespaces)** | Firebase/Marketing/Cron/Auth/Voucher logic discoverable by path |
| **Test tree mirrors service tree** | Find any service's test by path |
| **`database/factories/` with documented `BaseFactory`** | Test-data construction is now discoverable, with its constraints stated up front |
| Facade + Registry patterns | Clear entry points into decomposed domains |
| `docs/` (38 plan files + QA + service guides) | Design rationale for recent work |

### Weaknesses

| Issue | Impact |
|-------|--------|
| Only 5 interfaces — 113 services still concrete-only | Contract discovery works in `Auth/` only |
| Query classes in `Http/` | Counter-intuitive location (93 classes) |
| **43** flat root-level services | Notification/commerce/integration/search still ungrouped |
| 4 database connections | Cross-database relationships unclear |
| Five files >1,100 lines | `ChapterService` 1,522, `MarketingV2Query` 1,418, `UserProgramService` 1,410, `FirebaseNotificationQuery` 1,261, `UserQuery` 1,180 |
| API controllers carry no return types | Signature intent invisible without reading the service |

---

## AI Success/Failure Scenarios

### Scenario 1: "Add a new Firebase notification campaign"

| Factor | Assessment |
|--------|-----------|
| Finding the pattern | HIGH — 8 isolated campaign services to copy |
| Implementation | HIGH — small, single-purpose, registry-driven |
| Testing | HIGH — mirrored unit test per campaign exists |
| **Overall likelihood** | **80% correct on first attempt** (unchanged) |

### Scenario 2: "Add a new admin CRUD screen"

| Factor | Assessment |
|--------|-----------|
| Finding the pattern | HIGH — 56 `Http/Requests/Admin/**` classes across 25 controllers |
| Controller + Form Request | HIGH — inline validation down to 6 sites, all in one file |
| Query layer | HIGH — 94% method-level PHPDoc (though only 49% return types) |
| Test creation | HIGH — 89 feature tests to copy; `Program`/`Coupon`/`Voucher` factories now exist |
| **Overall likelihood** | **82% correct on first attempt** (was 80%) |

### Scenario 3: "Add a new API endpoint for user preferences"

| Factor | Assessment |
|--------|-----------|
| Route registration | HIGH — clear pattern in `api.php` (78 routes) |
| Input validation | **LOW — API controllers use neither Form Requests nor `validate()`**; input flows untyped through `getPostData()` |
| Signature typing | **LOW — 6 return types across 72 API controller methods** |
| Service method | HIGH — services are 100% return-typed and 73% PHPDoc'd |
| Test creation | MEDIUM — feature tests exist to copy |
| **Overall likelihood** | **70% correct on first attempt** (unchanged — the API surface was not touched) |

### Scenario 4: "Fix a bug in the auth / login flow"

| Factor | Assessment |
|--------|-----------|
| Finding relevant code | **HIGH — `BaseAuthService` is 234 lines and delegates by name** (was 1,465) |
| Understanding the flow | **HIGH — 5 deps, 5 interfaces, `strict_types` on** (was LOW-MEDIUM, 33 deps) |
| Making the fix | HIGH — typed params, PHPStan clean on these files |
| Verifying the fix | **MEDIUM-HIGH — 5 dedicated unit test files added this period** (was LOW) |
| **Overall likelihood** | **70% correct on first attempt** (was 40%) |

### Scenario 5: "Write a unit test for an existing service" — NEW

| Factor | Assessment |
|--------|-----------|
| Finding where the file goes | HIGH — `tests/Unit/Services/` mirrors `app/Services/` |
| Building test data | **MEDIUM — 8 factories exist, but `make()`-only and 86 models still uncovered** |
| Copying a pattern | HIGH — 80 service unit tests, Pest `describe()`/`it()` throughout |
| Style compliance | **LOW-MEDIUM — `tests/` already carries 93 Pint violations, so there is no clean example to imitate** |
| **Overall likelihood** | **72% correct on first attempt** |

---

## Actionable Recommendations

### Priority 1: High Impact, Low Effort — COMPLETED

#### 1.1 ~~Add return type hints to all service methods~~ DONE (2026-03-12) — verified 706/706 in `app/Services`
#### 1.2 ~~Add parameter type hints to all public methods~~ DONE (2026-03-12)
#### 1.3 ~~Create a `Platform` enum and replace magic strings~~ DONE (2026-03-13)
#### 1.4 ~~Extract controller validation to base method~~ DONE (2026-03-13)
#### 1.5 ~~Fix `userJournyLog` typo~~ DONE (2026-03-13)
#### 1.6 ~~Build V3 API layer with standardized patterns~~ DONE (2026-03-18), **REMOVED** (2026-03-24)
#### 1.7 ~~Add PHPDoc to all service methods~~ DONE (2026-03-24)
#### 1.8 ~~Fix service layer architectural violations~~ DONE (2026-03-26)
#### 1.9 ~~Decompose `FirebaseBusinessService` god class~~ DONE (2026-06-30)
#### 1.10 ~~Split Marketing & Cron services into domain sub-namespaces~~ DONE (2026-06-30)
#### 1.11 ~~Expand service unit test coverage (mirror service tree)~~ DONE (2026-06-30)

### Priority 0: Do These First (Score impact: +4-6 points, ~2 days total)

#### 0.1 ~~Get `vendor/bin/phpstan analyse` back to green~~ — SUBSTANTIALLY DONE (2026-08-21)

**Current state:** 16 errors → **4**, all `ignore.unmatched` / `ignore.count` bookkeeping; **zero genuine defects** | **Effort remaining:** 5 minutes
Every real error from the last report is fixed. Run `vendor/bin/phpstan analyse --generate-baseline --memory-limit=2G` to clear the four stale entries (`AcquisitionCronService`, `UserActivityService` ×3) and the gate passes.

#### 0.2 Set up CI (GitHub Actions) — **STILL TOP PRIORITY**

**Current state:** no `.github/` directory | **Effort:** 1 day
The suite runs green serially (115s) and in parallel (75s, 4 processes). A workflow running `vendor/bin/pest --parallel`, `vendor/bin/phpstan analyse`, and `vendor/bin/pint --test` on every PR converts three advisory gates into enforced ones. **Sequence matters: do 0.1 and 0.3 first, or the pipeline is red on its first run.**

#### 0.3 Bring `vendor/bin/pint --test` to green — **NEW**

**Current state:** **436 style issues across 799 files** (309 in `app/`, 93 in `tests/`) | **Effort:** half a day
Run `vendor/bin/pint`, review the diff, commit it as a single formatting-only change, then add `--test` to CI. Doing this *after* CI exists means either a permanently red pipeline or a whole-repo diff landing on top of feature work. Doing it now costs one reviewable commit.
Per project convention, prove the change is behaviour-neutral: the diff should be whitespace/import/quote-style only, and `vendor/bin/pest` must still report 2,522 passing.

### Priority 2: High Impact, Medium Effort (Score impact: +6-9 points)

#### 2.1 Expand Form Request validation to the API surface — STILL OPEN

**Current state:** 66 Form Requests across 35 controllers; **0 in `app/Http/Controllers/Api/`** | **Effort:** 1-2 days
The admin/web write surface is done — inline validation is 6 call sites, all in `NewYearEmailController`. What's left is the API surface, which uses neither Form Requests nor `validate()`. This is now the largest consistency gap in the codebase.

#### 2.2 Add return types to API controllers and query classes — **NEW, and the cheapest win available**

**Current state:** `app/Http/Controllers/Api` **6/72 (8%)**; `app/Http/Queries` **332/673 (49%)**; `app/Models` 59/93; `app/Http/Middleware` 5/11 | **Effort:** 1 day
Previous reports recorded this layer as "100% complete" because of a measurement error (see the Correction section). It is not. `CLAUDE.md` mandates a native return type on every method and names `Api/UserController` as a reference example — that file declares zero across six methods. Most of these are one-token edits (`: JsonResponse`, `: array`, `: Collection`), and PHPStan level 5 will verify each one.

#### 2.3 Add model factories for core models — SUBSTANTIALLY DONE (2026-08-21), extend

**Current state:** **9 factories** (`Admin`, `Coupon`, `Program`, `User`, `UserConfig`, `UserInfo`, `UserProgram`, `Voucher` + `BaseFactory`) | **Target:** the remaining high-traffic models | **Effort:** 1-2 days
Remaining priority models: `Chapter`, `Day`, `UserProfile`, `UserSubscription`, `UserDay`, `Exercise`. Two follow-ups matter as much as the count:
1. **Adoption** — only 13 of 188 test files call `::factory()`; the rest still hand-build fixtures.
2. **`make()`-only is a hard ceiling** — `create()` cannot work while `tbl_*` tables have no CREATE migrations. Adding test-only schema (or a `database/schema/*.sql` load step for the SQLite connection) would unlock persisted fixtures and is worth scoping separately.

#### 2.4 ~~Raise PHPStan level from 1 to 5~~ DONE (2026-07-18); gate now effectively green — see 0.1

**Current state:** Level **5/9** via larastan + a **2,896-line** baseline (down from 3,040; 478 grandfathered entries). Next step after 0.1 is working the baseline down.

#### 2.5 ~~Fix the suite's Mockery redeclaration error~~ DONE (2026-08-07)

#### 2.6 Add class-level docblocks — STILL OPEN

**Current state:** services **49%** (was 43%), controllers 36%, API controllers 7%, Form Requests 27%, middleware 10%, **enums 0%** | **Effort:** 1 day
`CLAUDE.md` requires a class-level PHPDoc on every class. Method-level coverage is 90-94% on the layers that matter; class headers remain the hole. Use `database/factories/BaseFactory.php` as the model — it documents constraints and pitfalls, not just purpose.

#### 2.7 Standardize error handling with a response trait

**Current state:** 5 competing patterns; `ApiResponse` trait used by only 13 of 77 controllers | **Target:** single `FormatsApiResponse` trait | **Effort:** 2-3 days

### Priority 3: Medium Impact, Higher Effort (Score impact: +5-8 points)

#### 3.1 Decompose the remaining 1,100+ line files — `BaseAuthService` DONE; `ChapterService` is now the target

```
ChapterService              1,522  <- now the largest file in app/, TOP TARGET
MarketingV2Query            1,418
UserProgramService          1,410
FirebaseNotificationQuery   1,261
UserQuery                   1,180
UserRegistrationService       851  <- new; well-structured but large

~~BaseAuthService  1,465~~ -> 234 lines / 5 deps / 4 extracted services  ✅ DONE 2026-08-21
```

**Use the auth split as the template.** It is the pattern that worked: extract a cohesive responsibility, define an interface for it, bind it in `AppServiceProvider`, add `declare(strict_types=1)`, and write a unit test per extracted class. `ChapterService` divides naturally into chapter progress, exercise handling, and content assembly.

**One lesson from this period:** extracting classes did not shorten methods — `buildUserData()` (141) and `checkAndUpdateUserProgram()` (120) moved intact. Split the long methods as part of the extraction, the way `createNewUser()` was (296 → 116 + 13 phase methods), or the complexity simply changes address.

#### 3.2 Break up `ModuleAnalyticsController::getModuleAnalytics()` (706 lines)

Unchanged for two periods. The single largest method in the codebase and 93% of its 757-line controller. The `ModuleAnalyticsQuery` + `ModuleAnalyticsRequest` extraction started this — finish it.

#### 3.3 Add `declare(strict_types=1)` to all files

**Current state:** **11 of 518** (was 1) | **Effort:** Automated via script + fix the type errors it surfaces
The 11 new auth/voucher files prove the pattern works here. Roll it out namespace by namespace, running `pest` after each.

#### 3.4 Group the 43 flat root-level services by domain

Unchanged for two periods. The domain-namespace pattern is now well established with nine examples.

```
app/Services/
├── Notification/   (Firebase facade, Postmark, SendGrid, Transactional)
├── Commerce/       (Coupon, Voucher, Billing)
├── Integration/    (Meta, Gympass, Bajaj, Discourse)
├── Search/         (Search, Typesense*, SynonymSync)
└── Core/           (remaining)
```

### Priority 4: Advanced (Score impact: +3-5 points)

| Task | Effort | Score Impact |
|------|--------|-------------|
| Extend interfaces beyond `Auth/`+`Voucher/` (5 exist, 113 services concrete-only) | 3 days | +3 |
| Replace remaining 701 loose comparisons (`==` -> `===`) | 1-2 days | +2 |
| Add test-only schema so factories can `create()` | 1-2 days | +2 |
| Move Query classes from `Http/` to `app/Queries/` | 1 day | +1 |
| Document model relation/scope methods (13% coverage) | 1 day | +1 |

---

## Implementation Roadmap

### Phase 1: Quick Wins — COMPLETED (2026-03-12 → 03-13)

| Task | Status | Score Impact |
|------|--------|-------------|
| ~~Add return/parameter types to all **service** files~~ | **DONE** (verified 706/706) | +8 |
| ~~Create `Platform` enum~~ | **DONE** | +1 |
| ~~Extract controller validation to base method~~ | **DONE** | +2 |
| ~~Fix `userJournyLog` typo~~ | **DONE** | +1 |

### Phase 1.5: PHPDoc Coverage — COMPLETED (2026-03-24 → 03-25)

| Task | Status |
|------|--------|
| ~~PHPDoc array shapes for V1 services~~ | **DONE** |
| ~~Model `@property` annotations~~ | **DONE** (97%) |
| ~~Query class method PHPDoc~~ | **DONE** (94%) |
| ~~Admin controller PHPDoc~~ | **DONE** (90%) |

### Phase 1.75: Architecture Cleanup — COMPLETED (2026-03-26)

| Task | Status | Score Impact |
|------|--------|-------------|
| ~~Extract CalculatesUtcOffset trait~~ | **DONE** | +1 |
| ~~Remove controller inheritance from services~~ | **DONE** | +1 |
| ~~Replace service locator with constructor DI~~ | **DONE** | +0.5 |
| ~~Optimize auth queries with column selection~~ | **DONE** | +0.5 |

### Phase 2: God-Class Decomposition & Testing — COMPLETED (2026-06-30)

| Task | Status | Score Impact |
|------|--------|-------------|
| ~~Decompose FirebaseBusinessService (2,619 → 228 facade)~~ | **DONE** | +3 |
| ~~Split Marketing into domain sub-namespace~~ | **DONE** | +1 |
| ~~Split Cron into domain services/processors~~ | **DONE** | +1 |
| ~~Expand tests 83 → 154 (mirror service tree)~~ | **DONE** | +2 |
| ~~Introduce Form Request validation (3 classes)~~ | **DONE (started)** | +1 |

### Phase 3: Standardization & Enforcement — Target 76 (71 → 74 delivered)

| Task | Effort | Score Impact |
|------|--------|-------------|
| ~~Raise PHPStan to level 5~~ | **DONE (2026-07-18)** | **+2** |
| ~~Fix Mockery suite isolation~~ | **DONE (2026-08-07)** | **+1** |
| ~~Admin controller/query test + PHPDoc sweep~~ | **DONE (2026-08-07)** | **+1** |
| ~~Fix the 16 PHPStan errors~~ | **DONE (2026-08-21)** — 4 bookkeeping entries left | **+2** |
| ~~Add 8+ model factories~~ | **DONE (2026-08-21)** | **+3** |
| **Regenerate the PHPStan baseline** | **5 min** | **+0.5** |
| **Run `pint` and commit the formatting fix (436 issues)** | **0.5 day** | **+1** |
| **Add CI (pest + phpstan + pint on PR)** | **1 day** | **+2** |
| Add return types to API controllers + queries | 1 day | +2 |
| Standardize error handling with response trait | 2-3 days | +2 |
| Expand Form Requests to the API surface | 2 days | +2 |
| Add class-level docblocks (services/controllers/enums) | 1 day | +1 |

### Phase 4: Structural Depth — Target Score: 84

| Task | Effort | Score Impact |
|------|--------|-------------|
| ~~Decompose BaseAuthService (1,465 → 234)~~ | **DONE (2026-08-21)** | **+3** |
| Decompose ChapterService (1,522 lines) | 3 days | +2 |
| Break up `getModuleAnalytics()` (706-line method) | 1 day | +1 |
| Decompose UserQuery (1,180) / MarketingV2Query (1,418) | 3 days | +2 |
| Split `UserRegistrationService` (851) further | 1 day | +1 |
| Add `declare(strict_types=1)` to all files (11/518 today) | 1 day | +2 |
| Group 43 flat root-level services by domain | 1 day | +1 |
| Extend interfaces to core service dependencies | 3 days | +3 |

### Projected Score Progression

```
Mar 9:   ███████████████████████░░░░░░░░░░░░░░░░░░░░░░░░░░░  45 (D)   <- Initial assessment
Mar 13:  ███████████████████████████░░░░░░░░░░░░░░░░░░░░░░░  53 (C-)  <- Phase 1 done
Mar 18:  ████████████████████████████████░░░░░░░░░░░░░░░░░░  63 (C)   <- V3 API done
Mar 24:  ██████████████████████████████░░░░░░░░░░░░░░░░░░░░  60 (C)   <- V3 removed, V1 PHPDoc
Mar 25:  ██████████████████████████████░░░░░░░░░░░░░░░░░░░░  61 (C)   <- Full PHPDoc all layers
Mar 26:  ███████████████████████████████░░░░░░░░░░░░░░░░░░░  62 (C)   <- Architecture cleanup
Jun 30:  █████████████████████████████████░░░░░░░░░░░░░░░░░  66 (C)   <- God-class decomposition + testing
Jul 10:  ██████████████████████████████████░░░░░░░░░░░░░░░░  68 (C)   <- Admin-wide Form Requests (3 -> 55)
Jul 18:  ███████████████████████████████████░░░░░░░░░░░░░░░  70 (C+)  <- PHPStan level 1 -> 5
Aug 7:   ███████████████████████████████████░░░░░░░░░░░░░░░  71 (C+)  <- +21 tests, suite green; offset by red PHPStan
Aug 21:  █████████████████████████████████████░░░░░░░░░░░░░  74 (C+)  <- BaseAuthService 1,465->234, first 5 interfaces,
                                                                        factories 1->9, PHPStan 16->4 errors (0 genuine);
                                                                        offset by Pint 436 + return-type correction
Phase 3: ██████████████████████████████████████░░░░░░░░░░░  76 (C+)  <- CI + pint green + API return types + error trait
Phase 4: ██████████████████████████████████████████░░░░░░░  84 (B)
```

---

## Appendix A: Files Most Critical to Improve

| File | Lines | Why Critical | AI Difficulty |
|------|-------|-------------|---------------|
| `Services/ChapterService.php` | **1,522** | **Largest file in `app/`** — core program/chapter flow, 141-line `updateChapterStatus()`, 116-line `updateExercise()`. Top decomposition target. | HARD |
| `Http/Controllers/ModuleAnalyticsController.php` | 757 | Contains the **706-line** `getModuleAnalytics()` — largest method in the codebase, unchanged for two periods | HARD |
| `Http/Queries/MarketingV2Query.php` | 1,418 | Largest query class; five methods over 115 lines | HARD |
| `Services/User/UserProgramService.php` | 1,410 | Core user-program logic; 124-line `updateLanguage()` | HARD |
| `Http/Queries/FirebaseNotificationQuery.php` | 1,261 | Notification data layer | HARD |
| `Http/Queries/UserQuery.php` | 1,180 | Most-used query class | HARD |
| `Services/Auth/UserRegistrationService.php` | 851 | New; well-structured (13 phase methods) but the largest single piece of the auth split | MEDIUM |
| `Http/Controllers/NewYearEmailController.php` | 547 | Holds all 6 remaining inline `\Validator::make` call sites in the codebase | MEDIUM |
| `Services/ProgramService.php` | 504 | 266-line `getProgramSubscriptionDetails()` with queries in loops | MEDIUM |
| `Http/Controllers/Api/*.php` | — | **6 return types across 72 methods**; no Form Requests; input via untyped `getPostData()` | MEDIUM |
| `Services/Auth/BaseAuthService.php` | **234** | ~~Core auth god class~~ — **now a thin, interface-backed base** | **LOW** ✅ |
| `Services/FirebaseBusinessService.php` | 228 | Facade — safe; depend on campaign services directly | LOW |

## Appendix B: Grading Scale

| Score | Grade | Meaning |
|-------|-------|---------|
| 90-100 | A | AI can work autonomously with high accuracy |
| 80-89 | B | AI produces correct code most of the time |
| 70-79 | C+ | AI needs moderate human review |
| 60-69 | C | AI frequently needs correction |
| 50-59 | C- | AI requires significant guidance |
| 40-49 | D | AI struggles without heavy supervision |
| 0-39 | F | AI cannot reliably work with this codebase |

---

## Appendix C: How These Numbers Were Measured (2026-08-21)

All figures are measured, not estimated. Previous-period numbers were **re-measured** against the tree at `c81f619` (the last commit before this period, 2026-08-06) rather than carried forward — which is how the return-type error described above was found.

```bash
# File / class counts (current tree)
find app -name "*.php" | wc -l                      # 518
find app/Services -name "*.php" | wc -l             # 118
find app/Services -maxdepth 1 -name "*.php" | wc -l # 43 (flat)
find tests -name "*.php" | wc -l                    # 188
find app/Http/Requests -name "*.php" | wc -l        # 66
find database/factories -name "*.php" | wc -l       # 9
grep -rl "declare(strict_types=1)" app/ | wc -l     # 11
grep -rl "^interface " app/ | wc -l                 # 5

# Quality gates (run inside the laradock workspace container)
vendor/bin/pest                                 # 2,522 pass / 10 skip / 0 fail, 115s
vendor/bin/pest --parallel                      # same, 75s, 4 processes
vendor/bin/phpstan analyse --memory-limit=2G    # 4 errors, all ignore.unmatched/ignore.count
vendor/bin/pint --test                          # FAIL: 799 files, 436 style issues
vendor/bin/pint --test app                      # FAIL: 518 files, 309 style issues
vendor/bin/pint --test tests                    # FAIL: 188 files,  93 style issues

# Loose comparisons (identical regex against both trees)
grep -rEo '[^=!<>]==[^=]|!=[^=]' app/ --include="*.php" | wc -l   # 701 (was 706)

# Historical baseline
git archive c81f619 | tar -x -C /tmp/baseline    # re-measure the 2026-08-07 tree
```

**Docblock, return-type, and long-method figures** come from a `token_get_all()`-based PHP script run over both trees. Two methodology notes:

1. **Return types exclude constructors**, which cannot declare one in PHP. Including them (as the raw denominator would) understates coverage; using only the typed methods as the denominator — the previous reports' error — overstates it to a fixed 100%.
2. **Method length** is measured from the `function` keyword's line to the line of its closing brace. The previous report's figure of "36 methods > 100 lines" was produced by a different script; re-running the current script against `c81f619` yields **40**, which is the number compared against today's **39**.

---

*Report generated by Claude Code. Last updated 2026-08-21 after a 16-commit period whose centrepiece was the decomposition of `BaseAuthService`. Score moved 71 → 74 (C+). The headline: the codebase's oldest and highest-risk god class — 1,465 lines and ~33 constructor dependencies, named the top structural target in five consecutive reports — is now a 234-line base delegating through **the first five interfaces this codebase has ever had**, with `declare(strict_types=1)` on every new file and a unit test per extracted service. Alongside it, model factories went 1 → 9, closing the "single biggest testing gap" (with the real caveat that they are `make()`-only, because `tbl_*` tables have no CREATE migrations), and PHPStan went from 16 errors to 4 — none of them genuine defects, just a stale baseline. The suite is green at 2,522 passing, serially and in parallel. Two things held the gain to +3. First, `vendor/bin/pint --test` fails with **436 style issues** — a gate nobody had measured, and one that would turn the proposed CI red on its first run. Second, a correction: **return-type coverage across `app/` is 73%, not the 100% claimed since July** — that figure counted only the methods that already had return types. `app/Services` genuinely is 100%, but API controllers sit at **6 of 72**. The next three actions are small and unambiguous, roughly 1.5 days total: regenerate the PHPStan baseline, run `pint` and commit the formatting fix, then stand up CI to run all three gates on every PR. After that: return types on the API and query layers, Form Requests on the API surface, and `ChapterService` (1,522) — which inherits the crown `BaseAuthService` just gave up.*
