# Dimension: Implementation Thinness

Evaluate whether the repo embodies the erp-kit principle of **thin implementations**: resolvers should delegate to module commands rather than embed logic, custom modules should be small and self-contained (lib/ kept to types only), and frontend pages should rely on `@tailor-platform/app-shell` instead of bespoke layout components.

## Inputs

- `REPO_ROOT`
- `APP_ROOT` (optional) — path under `REPO_ROOT` to one app (e.g. `apps/my-shop`)
- `MODULES_ROOT` (optional) — path under `REPO_ROOT` to the modules directory (e.g. `modules`)

The agent decides which to pass to the measure CLI based on what exists in the repo. Provide both when possible.

## Procedure

### 1. Run the measurement CLI

```bash
npx erp-kit internal measure thin --app-root <APP_ROOT> --modules-root <MODULES_ROOT>
```

If neither flag is provided the result is `{}` — surface a finding and skip scoring.

The CLI returns JSON shaped like:

```json
{
  "resolvers": {
    "count": 24,
    "avgLoC": 42,
    "maxLoC": 180,
    "filesOverThreshold": [{ "path": "...", "loc": 250 }]
  },
  "commands": {
    "count": 38,
    "avgLoC": 28,
    "handWrittenRatio": 0.72,
    "libNonTypesFiles": ["modules/sales/lib/helpers.ts"]
  },
  "frontend": {
    "pages": { "count": 18 },
    "jsxComposition": {
      "appShellTags": 142,
      "rawHtmlTags": 38,
      "otherLibraryTags": 5,
      "appShellRatio": 0.77
    },
    "rawHtmlHeavyPages": [
      { "path": "frontend/src/pages/legacy/page.tsx", "appShellRatio": 0.2, "rawHtmlTags": 18 }
    ],
    "customComponents": 12
  }
}
```

If the CLI is not available (older erp-kit), return `{ "score": null, "status": "tool-unavailable", "findings": [{ "severity": "info", "message": "measure thin command not available in this erp-kit version; dimension skipped." }] }`.

### 2. Interpret each sub-metric

For each present section, judge against erp-kit conventions.

#### Resolvers (when `resolvers` is present)

- **avgLoC**: < 80 ideal, 80-150 acceptable, > 150 suggests embedded logic. Penalty grows with average.
- **filesOverThreshold**: each entry is a resolver > 200 lines (the same threshold used elsewhere in erp-kit). Each occurrence is a strong signal that logic belongs in a module command.

#### Commands (when `commands` is present)

- **avgLoC**: < 60 ideal. Higher means commands are doing too much.
- **handWrittenRatio**: how much of `command/*.ts` is hand-written vs `.generated.ts`. Very high (e.g. > 0.9) can mean generators are under-used; very low (< 0.3) usually fine.
- **libNonTypesFiles**: per the structure convention, `lib/` should contain only `types.ts` and generated files. Each extra file is a violation and should be penalised — **unless the file content is pure type declarations** (look at the file before penalising).

#### Frontend (when `frontend` is present)

JSX tags found in page-tree `.tsx` files are bucketed by import origin:

- **app-shell tag** — imported from `@tailor-platform/app-shell` (e.g. `<Layout>`, `<Button>`) → counted as the numerator
- **raw HTML tag** — lowercase opener (e.g. `<div>`, `<span>`, `<p>`) → in the denominator (penalty)
- **other-library tag** — imported from any other external package, excluding `react`/`react-dom` (e.g. `<DataGrid>` from MUI) → in the denominator + flat penalty for mere presence
- **local component** — imported via relative path or undefined → not counted (neutral; the heuristic can't tell whether a local component is a thin wrapper or a heavy bespoke layout)

Metrics surfaced from this bucketing:

- **jsxComposition.appShellRatio**: ratio of app-shell tags vs (app-shell + raw HTML + other-library tags) across all page-tree `.tsx` files. > 0.85 ideal, < 0.6 suggests pages are built with raw HTML or third-party UI kits.
- **jsxComposition.rawHtmlTags**: total count of raw HTML tags across pages. High absolute count even with good ratio is a yellow flag.
- **jsxComposition.otherLibraryTags**: total count of other-library tags. Any non-zero value is a smell — erp-kit assumes app-shell is the UI vocabulary.
- **rawHtmlHeavyPages**: pages with `appShellRatio < 0.5` and `rawHtmlTags >= 5`. These are the worst offenders — list them individually in findings.
- **customComponents**: number of `.tsx` files in `frontend/src/components/`. A small number is fine. Larger numbers (e.g. > 20) hint that the app is rebuilding things app-shell already provides.

### 3. Score

Start at 100 and subtract. Thresholds below are anchored to the scaffold-bundled apps' actual measurements (= roughly: resolver avg 65-68 LoC, command avg 90 LoC in built-in modules, JSX appShellRatio ~0.58). Pure-noise tuning will likely happen after a release cycle of real-world data.

| Signal | Subtract |
| ------ | -------- |
| Resolver `avgLoC` > 100 | 2 per 10 LoC above 100, cap 15 |
| Each resolver in `filesOverThreshold` (= over 200 LoC) | 5, cap 25 |
| Command `avgLoC` > 120 | 2 per 10 LoC above 120, cap 10 |
| `commands.handWrittenRatio` > 0.9 with `commands.count` > 5 | 5 |
| Each `libNonTypesFiles` entry (after content check, excluding `_*.ts` stubs) | 5, cap 20 |
| `frontend.jsxComposition.appShellRatio` < 0.55 | 3 per 0.05 below, cap 15 |
| Each `frontend.rawHtmlHeavyPages` entry | 3, cap 15 |
| `frontend.jsxComposition.otherLibraryTags` > 0 | 5 flat (different UI kit smell) |
| `frontend.customComponents` > 20 | 5 (+5 if > 40) |

Clamp to `[0, 100]`.

Each subtraction must include a finding so the user understands why points were deducted.

> **Note:** All numeric thresholds in this table are initial values calibrated against the scaffold-bundled apps. They are expected to be re-tuned once enough real-world data accumulates. Report findings even when a threshold is borderline — the human reviewer is the final judge.

### 4. Output

Return JSON with the standard dimension shape:

```json
{
  "dimension": "thinness",
  "score": 78,
  "findings": [
    {
      "severity": "info",
      "message": "Resolvers: 24 files, avg 42 LoC, max 180 — within ideal range."
    },
    {
      "severity": "warning",
      "message": "Command avgLoC 78 exceeds the 60 ideal; consider extracting helpers or splitting commands."
    },
    {
      "severity": "warning",
      "message": "modules/sales/lib/helpers.ts is not a types file — `lib/` should contain only types + generated files."
    },
    {
      "severity": "info",
      "message": "AppShell adoption: 94% (17/18 pages). Healthy."
    }
  ]
}
```

`severity` mapping in the report:

- positive observations and within-range metrics → `info` (collapsed)
- thresholds exceeded but workable → `warning`
- structural violations (lib/, very long resolvers) → `warning` or `error` depending on magnitude
