docs(plan): deptrac architecture-fitness integration plan

9-task plan closing the 4 open A6 architecture-fitness gaps
(conformance, layer-direction, C4 drift, active design) via
deptrac as a lefthook job-10 layer-dependency gate. + cspell vocab.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Дмитрий
2026-05-17 11:07:09 +03:00
parent f9bedb6aad
commit 507c4d869a
2 changed files with 561 additions and 0 deletions
+6
View File
@@ -1360,3 +1360,9 @@ PRD
automazeio
prds
Vivek
# deptrac architecture-fitness integration (2026-05-17)
deptrac
qossmic
mermaidjs
graphviz
@@ -0,0 +1,555 @@
# deptrac Architecture-Fitness Integration Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Close the four open architecture-fitness gaps inside map section A6 — active feature-architecture design, architecture conformance, layer/dependency-direction enforcement, and C4-component-diagram drift — by integrating **deptrac** as a declarative, zero-LLM layer-dependency gate wired into the lefthook pre-commit chain.
**Architecture:** A6 «Архитектура систем» currently has three nodes (adr-kit #36 / mermaid-skill #37 / architecture-patterns #38) covering *record / visualize / reference* — but nothing **enforces** that code keeps matching the chosen layered architecture beyond `adr-judge`'s narrow regex scope. deptrac is a deterministic static-analysis tool (no LLM, matches the AK6 principle adr-kit was built under): it parses the `App\` source into named layers (Controller / Service / Model / Job / …) and fails the build on disallowed dependency directions. Pre-existing violations are captured once into a baseline so the gate is green from day one and only catches *new* drift. deptrac's code-derived graph output doubles as a drift-proof C4-component diagram. deptrac becomes the 4th architecture-tooling tool — A6 goes 3 → 4 nodes.
**Tech Stack:** deptrac (`qossmic/deptrac` — PHP static analysis, declarative YAML, BSD-3); composer dev-dependency in `app/` (PHAR-in-`bin/` fallback — DT1); lefthook (pre-commit job 10); the project normative docs; `docs/automation-graph.html` (vis.js).
---
## Sequencing (locked 2026-05-17)
This is the **4th** tooling-integration epic. The A6, D3, and C9 plans lock a strict, never-interleaved order because all four epics touch the same shared files (the map, the 4 normative docs, the Tooling counter, `cspell-words.txt`). deptrac joins that queue:
- **A6** architecture-tooling — ✅ complete, on `origin/main`.
- **D3** audit-risk-tooling — must run to completion and push **first**.
- **C9** project-management-tooling — runs after D3.
- **deptrac** (this plan) — runs after D3; its slot **relative to C9** (before or after) is the user's call at the Execution Handoff. Both orders are valid — deptrac shares no logical dependency with C9.
Task 1 forks the working branch from the **then-current** `origin/main` (not hard-coded). The Tooling registry number is **runtime-resolved** (DT-NUM) — never hard-code a number before reading the live counter; A6 took #36-38, D3 claims #39-40, C9 claims #41(-42).
---
## Tool Identity (verified 2026-05-17 — re-verify in Task 1)
| Item | Value |
|---|---|
| Tool | **deptrac** — PHP architecture layer/dependency enforcement |
| Package | `qossmic/deptrac` (Composer) — **Task 1 re-confirms the current package name, major version, PHP 8.3 / Laravel 13 compatibility, and the collector-config syntax** |
| License | BSD-3-Clause (permissive) |
| Install mode | Composer **dev-dependency** in `app/`; **fallback** = PHAR in `bin/deptrac.phar` if the dependency resolver conflicts (DT1) |
| Hooks | None — deptrac is a CLI tool, registers no Claude Code lifecycle hooks |
| LLM cost | Zero — pure static analysis (AST), no API calls (AK6-aligned) |
| Category | off-phase, **architecture-tooling** — 4th tool of that subcategory (with #36-38) |
**Out of scope (deliberate — YAGNI).** JS-side module-boundary enforcement for `resources/js` (`eslint-plugin-boundaries` / `dependency-cruiser`) is a separate future epic. This plan closes the **PHP/backend** architecture-fitness gaps only. Context/container-level C4 drift (external systems — Yandex Cloud, Unisender, JivoSite, Sentry) is inherently hand-maintained; it is covered by a §8 self-review checklist line (Task 7), not by tooling.
---
## Design Decisions & Conflict Audit
Pattern follows the AK1-AK6 (A6) / TB1 (D3) / CP-PG (C9) audits. Verified against `lefthook.yml`, `app/composer.json`, the `app/app/` tree, `app/phpstan.neon`, and the A6/D3/C9 plans.
| # | Sev | Conflict | Resolution (locked) |
|---|---|---|---|
| DT1 | 🟡 | `composer require --dev qossmic/deptrac` may conflict with Laravel 13's dependency tree (deptrac historically ships isolated). | Task 2: try the composer dev-dep first. If the resolver conflicts → fallback to a pinned `bin/deptrac.phar` (the project already vendors `bin/gitleaks.exe`, `bin/squawk.exe`, `bin/lychee.exe` this way). Decision criterion + both paths are in Task 2. |
| DT2 | 🟢 | deptrac becomes the 10th pre-commit job — adds latency per commit. | deptrac on a codebase this size analyses in ~1-3 s. Measured in Task 5 Step 4; recorded. `glob: "app/**/*.php"` scopes the job to PHP changes only. |
| DT3 | 🟡 | The **first** `deptrac analyse` will report pre-existing layer violations in current `app/` code → job 10 would block **every** commit. | **The headline risk.** Task 4 generates `app/deptrac.baseline.yaml` (`deptrac analyse --formatter=baseline`) capturing all current violations; job 10 then fails only on **new** drift. Same philosophy as `app/phpstan-baseline.neon`. The baseline count is recorded as architecture debt in `docs/architecture/`. |
| DT4 | 🟢 | Overlap with Larastan #12 (§5 п.6 — no two tools per task). | Different tasks: Larastan = type-level bug detection (PHPStan); deptrac = layer-dependency graph. Not a duplicate. Stated explicitly in the Tooling entry (Task 7). |
| DT5 | 🟢 | Overlap with adr-kit's `adr-judge` #36 — both "architecture enforcement" in lefthook. | Complementary, different mechanism: `adr-judge` = declarative regex on ADR `## Enforcement` text blocks; deptrac = AST-level layer-dependency graph. Documented in the Tooling entry + an ADR (Task 3 Step 5). |
| DT6 | 🟢 | The project nests Laravel at `app/`, so the `App\` source is `app/app/`. | deptrac config lives at `app/deptrac.yaml`; `paths: [app]` resolves to `app/app/`. lefthook job 10 uses `root: "app/"`. |
| DT7 | 🟢 | New `deptrac.yaml` / `deptrac.baseline.yaml` files. | `.yaml` — no pre-commit lint job touches it (squawk = `*.sql`, cspell/markdownlint = `*.md`). No lint conflict. |
| DT8 | 🟢 | Native Windows (no Docker / nested-virt — see `project_phase1_strategy`). | deptrac is pure PHP, runs via `php`. No extension/virtualization dependency (unlike pg_partman). |
| DT-NUM | 🟡 | A6 = #36-38, D3 = #39-40, C9 = #41(-42). deptrac must not collide. | Task 7 reads the **live** `docs/Tooling_v8_3.md` Прил. Н §0 counter and assigns `counter + 1`. Never hard-code. |
---
## File Structure
| File | Created / Modified | Responsibility |
|---|---|---|
| `app/deptrac.yaml` | Create | deptrac layer definitions + dependency ruleset |
| `app/deptrac.baseline.yaml` | Create | Baseline of pre-existing violations (DT3) |
| `app/composer.json` + `app/composer.lock` | Modify | deptrac dev-dependency (DT1 primary path) |
| `bin/deptrac.phar` | Create *(conditional — DT1 fallback only)* | Vendored deptrac PHAR if the composer resolver conflicts |
| `lefthook.yml` | Modify | New pre-commit **job 10** `deptrac` |
| `docs/architecture/c4-component-layers.md` | Create | Code-derived layer/component diagram (gap 4) + baseline-debt note |
| `docs/adr/ADR-005-architecture-fitness-deptrac.md` | Create | ADR recording the layer model + deptrac decision (reuses adr-kit from A6) |
| `docs/Tooling_v8_3.md` | Modify | Прил. Н — new architecture-tooling subsection + §0 counter bump |
| `docs/Plugin_stack_rules_v1.md` | Modify | R10.1 Блок 1 — new deptrac row |
| `docs/Pravila_raboty_Claude_v1_1.md` | Modify | §13.2 — extend the architecture-tooling category note |
| `CLAUDE.md` | Modify (**via claude-md-management only** — §5 п.10) | §3 title count, §1 row 2b count, new §3.3 row, §6 paragraph |
| `docs/CHANGELOG_claude_md.md` | Modify | CLAUDE.md version-bump entry |
| `docs/automation-graph.html` | Modify | New `deptrac` node → `NODE_SECTION` A6; header metrics |
| `cspell-words.txt` | Modify | deptrac vocabulary (`deptrac`, `qossmic`, `Deptrac`, …) |
---
## Task 1: Pre-flight — branch, baseline, fact-check, spike
**Files:** none modified (read-only) except a new branch.
- [ ] **Step 1: Confirm tree state and create the working branch**
```bash
cd "c:/моя/проекты/портал crm/Документация"
git status --short
git fetch origin
git checkout -b feat/deptrac-architecture-fitness origin/main
git rev-parse --short HEAD
```
Expected: D3 (and, per the user's chosen slot, C9) are already on `origin/main`. Record the `origin/main` HEAD SHA as the regression baseline. Push pattern at the end: `git push origin feat/deptrac-architecture-fitness:main`.
- [ ] **Step 2: Baseline regression**
Run `/regression quick`. Expected: GREEN. Record the last green Pest / Vitest counts from memory `project_state.md`. This epic changes **no** `app/` runtime code → the Task 9 run must match exactly.
- [ ] **Step 3: Snapshot the hook chain**
Read `.claude/settings.json` and `~/.claude/settings.json`; record every lifecycle hook. deptrac registers none — this snapshot is the Task 9 comparison baseline.
- [ ] **Step 4: Fact-check deptrac (DT1)**
WebFetch `https://github.com/qossmic/deptrac` and the Packagist page. Confirm and record:
- Current Composer package name + latest major version.
- PHP 8.3 / Laravel 13 compatibility (deptrac analyses source, does not load the app — compatibility is just the PHP runtime version).
- The collector config syntax for the installed major (`type: directory` path-regex vs `type: classLike` namespace-regex) — Task 3 writes the config for **this** syntax.
- The available `--formatter` values (specifically whether `mermaidjs` exists — Task 6 uses it; fallback `graphviz`).
If the current major's config schema differs materially from the Task 3 example below → adjust Task 3's config to match; note the deviation.
- [ ] **Step 5: Spike — run deptrac once on the real codebase**
Install deptrac into a throwaway location (do **not** commit yet) and run it once to learn the real violation count — this sizes DT3:
```bash
cd app
composer require --dev qossmic/deptrac --no-interaction --dry-run
```
Record whether `--dry-run` reports a dependency conflict (drives Task 2's path). Then do a real throwaway install + a single `vendor/bin/deptrac analyse` against a *minimal* temp config (one `Service`/`Model` layer pair) just to confirm the binary runs on Windows and prints a violation report. Record the rough violation count. Revert the throwaway install (`git checkout app/composer.json app/composer.lock`) — Task 2 does the real, committed install.
No repo files committed in Task 1.
---
## Task 2: Install deptrac
**Files:** Modify `app/composer.json`, `app/composer.lock`**or** Create `bin/deptrac.phar` (DT1 fallback).
- [ ] **Step 1: Install — primary path (composer dev-dependency)**
If Task 1 Step 5 reported **no** resolver conflict:
```bash
cd app
composer require --dev qossmic/deptrac --no-interaction
php vendor/bin/deptrac --version
```
Expected: deptrac added under `require-dev` in `app/composer.json`; `vendor/bin/deptrac` exists; `--version` prints the version. Record it.
- [ ] **Step 2: Install — fallback path (PHAR in `bin/`)**
Run this **only if** Step 1's `composer require` failed the dependency resolver. Download the pinned PHAR release asset from `https://github.com/qossmic/deptrac/releases` into `bin/deptrac.phar`:
```bash
curl -L -o bin/deptrac.phar https://github.com/qossmic/deptrac/releases/download/<version>/deptrac.phar
php bin/deptrac.phar --version
```
Expected: `php bin/deptrac.phar --version` prints the version. Record which path (Step 1 or Step 2) was taken — every later `deptrac` invocation in this plan uses `php vendor/bin/deptrac` (Step 1) **or** `php ../bin/deptrac.phar` run from `app/` (Step 2).
- [ ] **Step 3: Verify the offline security audit still passes**
```bash
cd app && composer audit --locked
```
Expected: 0 advisories (Roave already gates installs; this confirms deptrac added none).
- [ ] **Step 4: Commit**
Primary path:
```bash
git add app/composer.json app/composer.lock
git commit -m "build(deptrac): add deptrac as a composer dev-dependency (DT1)"
```
Fallback path:
```bash
git add bin/deptrac.phar
git commit -m "build(deptrac): vendor deptrac PHAR into bin/ (DT1 fallback)"
```
---
## Task 3: Author `deptrac.yaml` — layers + conservative ruleset
**Files:** Create `app/deptrac.yaml`; Create `docs/adr/ADR-005-architecture-fitness-deptrac.md`.
- [ ] **Step 1: Write the deptrac config**
Create `app/deptrac.yaml` (adjust the collector `type` to the syntax recorded in Task 1 Step 4 — the example uses the `type: directory` path-regex form):
```yaml
deptrac:
paths:
- ./app
layers:
- name: Controller
collectors: [{ type: directory, value: app/Http/Controllers/.* }]
- name: Request
collectors: [{ type: directory, value: app/Http/Requests/.* }]
- name: Resource
collectors: [{ type: directory, value: app/Http/Resources/.* }]
- name: Middleware
collectors: [{ type: directory, value: app/Http/Middleware/.* }]
- name: Service
collectors: [{ type: directory, value: app/Services/.* }]
- name: Job
collectors: [{ type: directory, value: app/Jobs/.* }]
- name: Console
collectors: [{ type: directory, value: app/Console/.* }]
- name: Repository
collectors: [{ type: directory, value: app/Repositories/.* }]
- name: Model
collectors: [{ type: directory, value: app/Models/.* }]
- name: Mail
collectors: [{ type: directory, value: app/Mail/.* }]
- name: Rule
collectors: [{ type: directory, value: app/Rules/.* }]
- name: Exception
collectors: [{ type: directory, value: app/Exceptions/.* }]
- name: Provider
collectors: [{ type: directory, value: app/Providers/.* }]
ruleset:
# Conservative ruleset — enforces only the architecturally-wrong directions
# (inward/upward deps). Whatever current code violates is captured by the
# Task 4 baseline; this gate then catches only NEW drift.
Controller: [Service, Request, Resource, Model, Job, Mail, Repository, Rule, Exception]
Middleware: [Service, Model, Exception]
Service: [Service, Model, Repository, Job, Mail, Rule, Exception]
Job: [Service, Model, Repository, Mail, Exception]
Console: [Service, Model, Repository, Job, Mail, Exception]
Repository: [Model, Exception]
Request: [Rule, Model]
Resource: [Model]
Rule: [Model]
Mail: [Model]
Model: ~ # bottom layer — depends on nothing in App\
Provider: [Controller, Service, Job, Console, Repository, Model, Mail, Middleware, Request, Resource, Rule, Exception]
```
- [ ] **Step 2: Run deptrac — see the current state (the "failing test")**
Primary: `cd app && php vendor/bin/deptrac analyse --no-progress` (fallback: `cd app && php ../bin/deptrac.phar analyse --no-progress`).
Expected: deptrac parses the config and prints a violation report. If the config has a **schema error**, deptrac prints the offending key — fix per its message and re-run. Record the violation count + the uncovered-class count. A non-zero violation count here is expected and correct (it is the architecture debt the baseline will capture).
- [ ] **Step 3: Write ADR-005**
Create `docs/adr/ADR-005-architecture-fitness-deptrac.md` (Nygard format — mirror the shape of `docs/adr/ADR-000`..`ADR-003`):
```markdown
# ADR-005: Architecture-fitness enforcement via deptrac
- **Status:** Accepted
- **Date:** 2026-05-17
- **Deciders:** Дмитрий
## Context
Map section A6 had tools to *record* (adr-kit), *visualize* (mermaid-skill) and
*reference* (architecture-patterns) architecture — but nothing enforced that the
code keeps matching the layered architecture (Controller → Service → Model …).
`adr-judge` enforces only what is hand-written as a regex in an ADR Enforcement
block — too narrow for dependency-direction rules.
## Decision
- Adopt **deptrac** — a declarative, zero-LLM static-analysis tool — as the
layer-dependency gate, wired as lefthook pre-commit job 10.
- The layer model and ruleset are defined in `app/deptrac.yaml` (conservative —
enforces only inward/upward-violating directions).
- Pre-existing violations are captured in `app/deptrac.baseline.yaml`; the gate
fails only on NEW drift. Reducing the baseline is tracked architecture debt.
## Consequences
- Positive: layer drift is caught at commit time, deterministically, free.
- Risk: a too-strict ruleset produces noise — mitigated by the conservative
ruleset + the baseline.
## Enforcement
The layer rules live in `app/deptrac.yaml`, enforced by lefthook job 10 — not by
an `adr-judge` regex. This ADR has no `adr-judge` Enforcement clause.
```
- [ ] **Step 4: Lint + commit**
```bash
npx markdownlint-cli2 "docs/adr/ADR-005-*.md"
npx cspell --no-progress --no-summary --no-gitignore "docs/adr/ADR-005-*.md"
```
Add valid flagged terms (`deptrac`, `qossmic`, `Nygard`, …) to `cspell-words.txt`. Then:
```bash
git add app/deptrac.yaml docs/adr/ADR-005-*.md cspell-words.txt
git commit -m "feat(deptrac): layer model + ruleset config + ADR-005"
```
---
## Task 4: Generate the baseline (DT3 — the headline risk)
**Files:** Create `app/deptrac.baseline.yaml`; Modify `app/deptrac.yaml`.
- [ ] **Step 1: Generate the baseline file**
```bash
cd app && php vendor/bin/deptrac analyse --formatter=baseline --output=deptrac.baseline.yaml
```
(Fallback binary: `php ../bin/deptrac.phar …`.) Expected: `app/deptrac.baseline.yaml` is created, listing every current violation as a skipped entry.
- [ ] **Step 2: Wire the baseline into the config**
Edit `app/deptrac.yaml` — add under the `deptrac:` key:
```yaml
baseline_file: ./deptrac.baseline.yaml
```
- [ ] **Step 3: Run deptrac — confirm GREEN (the "passing test")**
```bash
cd app && php vendor/bin/deptrac analyse --no-progress
```
Expected: **0 reported violations** (all pre-existing ones absorbed by the baseline). Exit code 0. If any violation still reports → the baseline did not capture it; regenerate (Step 1) and re-check.
- [ ] **Step 4: Commit**
```bash
git add app/deptrac.yaml app/deptrac.baseline.yaml
git commit -m "feat(deptrac): baseline pre-existing violations — gate green from day 1 (DT3)"
```
---
## Task 5: Wire lefthook pre-commit job 10
**Files:** Modify `lefthook.yml`.
- [ ] **Step 1: Add job 10**
Edit `lefthook.yml` — append after job 9 (`adr-judge`), inside `pre-commit.jobs`:
```yaml
# 10. deptrac — архитектурный гейт направления зависимостей / границ слоёв
# (Прил. Н — architecture-tooling). Анализирует app/app/** по слоям из
# app/deptrac.yaml; baseline_file гасит унаследованные нарушения (DT3) —
# job падает только на НОВОМ дрейфе. Без glob точечного анализа: deptrac
# строит граф классов, нужен весь app/. Чистый PHP, без LLM (AK6).
- name: deptrac
glob: "app/**/*.php"
root: "app/"
run: php vendor/bin/deptrac analyse --no-progress
fail_text: |
deptrac: staged-изменение нарушает направление зависимостей между
слоями (см. file:line выше и app/deptrac.yaml ruleset).
Если это осознанное архитектурное изменение — сначала обнови
app/deptrac.yaml (и при необходимости ADR-005), затем коммить.
```
Fallback-PHAR variant of the `run:` line: `run: php ../bin/deptrac.phar analyse --no-progress` — use whichever Task 2 path was taken.
- [ ] **Step 2: Verify the full chain runs**
```bash
npx lefthook run pre-commit
```
Expected: all 10 jobs execute; job 10 `deptrac` runs and reports 0 violations (baseline applied). Record job 10's wall-time (DT2).
- [ ] **Step 3: Red-green — prove the gate actually catches drift**
Introduce a deliberate violation, confirm deptrac flags it, then revert:
```bash
# pick a Model and make it import a Service (a forbidden upward dependency)
```
Edit any file under `app/app/Models/` to add `use App\Services\NotificationService;` and reference it. Run `cd app && php vendor/bin/deptrac analyse --no-progress`.
Expected: **deptrac reports 1 violation** (`Model must not depend on Service`), exit code non-zero. Then revert the edit (`git checkout app/app/Models/<file>`) and re-run — expected 0 violations again. This is the red-green proof that job 10 works.
- [ ] **Step 4: Commit**
```bash
git add lefthook.yml
git commit -m "ci(deptrac): wire deptrac as lefthook pre-commit job 10"
```
---
## Task 6: Code-derived C4-component diagram (gap 4)
**Files:** Create `docs/architecture/c4-component-layers.md`; Modify the `docs/architecture/` index.
- [ ] **Step 1: Generate the layer graph from code**
If Task 1 Step 4 confirmed a `mermaidjs` formatter:
```bash
cd app && php vendor/bin/deptrac analyse --formatter=mermaidjs --output=../docs/architecture/_deptrac-layers.mmd
```
Else use `--formatter=graphviz-dot --output=../docs/architecture/_deptrac-layers.dot`. The graph is **derived from the actual code** — it cannot drift.
- [ ] **Step 2: Create the diagram doc**
Create `docs/architecture/c4-component-layers.md`: a short intro, then the generated Mermaid graph embedded in a ```mermaid fence (or, for the graphviz fallback, a note + the committed `.dot` file). Include the recorded baseline violation count (Task 4 Step 1) as a one-line "architecture debt" figure. State that this is the **component-level** C4 view, derived from `app/deptrac.yaml`, regenerate via the Task 6 Step 1 command — and that **context/container-level** C4 (`c4-context.md`, external systems) stays hand-maintained.
- [ ] **Step 3: Link it from the architecture index**
Read the `docs/architecture/` index/README created by the A6 epic; add a link to `c4-component-layers.md` next to `c4-context.md`.
- [ ] **Step 4: Lint + commit**
```bash
npx markdownlint-cli2 "docs/architecture/c4-component-layers.md"
npx cspell --no-progress --no-summary --no-gitignore "docs/architecture/c4-component-layers.md"
git add docs/architecture/
git commit -m "docs(arch): code-derived C4 component-layer diagram from deptrac (gap 4)"
```
---
## Task 7: Normative registry sync (DT-NUM)
**Files:** Modify `docs/Tooling_v8_3.md`, `docs/Plugin_stack_rules_v1.md`, `docs/Pravila_raboty_Claude_v1_1.md`, `CLAUDE.md`, `docs/CHANGELOG_claude_md.md`, `cspell-words.txt`.
- [ ] **Step 1: Read the registry homes + the live counter (DT-NUM)**
Read for exact insertion points and the **current** counter: `docs/Tooling_v8_3.md` Прил. Н §0 + the last `§4.x` subsection (architecture-tooling = §4.11-4.13); `docs/Plugin_stack_rules_v1.md` R10.1 Блок 1; `docs/Pravila_raboty_Claude_v1_1.md` §13.2. Assign deptrac the number `counter + 1` — **after** the A6/D3/C9 entries already present. Record `#N`.
- [ ] **Step 2: Add the Tooling Прил. Н subsection**
Edit `docs/Tooling_v8_3.md`: add a `§4.x` subsection for `#N deptrac`, category **architecture-tooling** (off-phase — the 4th tool of that subcategory, with adr-kit/mermaid/architecture-patterns). Record: `qossmic/deptrac` BSD-3; install mode (composer dev-dep or `bin/deptrac.phar` — whichever Task 2 took); config `app/deptrac.yaml` + `app/deptrac.baseline.yaml`; lefthook job 10; zero-LLM (AK6-aligned); the DT4 boundary vs Larastan (#12 — type analysis ≠ layer graph) and DT5 vs adr-judge (#36 — regex ≠ AST graph). Bump the §0 counter and the Прил. Н version header. Mirror the shape of the §4.11 adr-kit entry.
- [ ] **Step 3: Add the PSR_v1 R10.1 row**
Edit `docs/Plugin_stack_rules_v1.md`: add a deptrac row to R10.1 Блок 1, category **architecture-tooling** — explicitly *outside* the UI-pool → no R6.0/R6.1 stack-filter, no R14 pipeline (same treatment as adr-kit/architecture-patterns). Bump the PSR_v1 version header.
- [ ] **Step 4: Extend the Pravila §13.2 note**
Edit `docs/Pravila_raboty_Claude_v1_1.md` §13.2: the **architecture-tooling** category note already exists (added by A6 for #36-38) — extend it to include `#N deptrac`. Re-read Pravila §0/§13 first to keep numbering consistent. Bump the Pravila version header.
- [ ] **Step 5: Update CLAUDE.md via the governed channel**
Invoke `/claude-md-management:claude-md-improver`. Apply: §3 title count bump (+1); §1 priority-chain row 2b count bump (+1); a new §3.3 row for `#N deptrac` (architecture-tooling, lefthook job 10, mirrors the #36 adr-kit row); a §6 paragraph noting the deptrac architecture-fitness integration. The plugin also writes the `docs/CHANGELOG_claude_md.md` entry and bumps the §0 cross-ref versions. **Do not** edit `CLAUDE.md` directly (§5 п.10).
- [ ] **Step 6: Lint + commit**
```bash
npx markdownlint-cli2 "docs/Tooling_v8_3.md" "docs/Plugin_stack_rules_v1.md" "docs/Pravila_raboty_Claude_v1_1.md" "docs/CHANGELOG_claude_md.md"
npx cspell --no-progress --no-summary --no-gitignore "docs/Tooling_v8_3.md" "docs/Plugin_stack_rules_v1.md" "docs/Pravila_raboty_Claude_v1_1.md"
git add docs/Tooling_v8_3.md docs/Plugin_stack_rules_v1.md docs/Pravila_raboty_Claude_v1_1.md CLAUDE.md docs/CHANGELOG_claude_md.md cspell-words.txt
git commit -m "docs(deptrac): register #N deptrac architecture-tooling (DT-NUM)"
```
---
## Task 8: Reflect deptrac on the map — extend section A6
**Files:** Modify `docs/automation-graph.html`.
- [ ] **Step 1: Read the structures to replicate**
In `docs/automation-graph.html` read, as templates, the A6 node `adr_kit` across `NODES`, `NODE_DETAILS`/`nd(...)`, `NODE_META`, `NODE_SECTION`, and the lefthook-job nodes (`lh_larastan`) — deptrac is both an architecture-tooling node and a lefthook job. Record the current node/edge counts from the header comment.
- [ ] **Step 2: Add the `deptrac` node**
Add to `NODES` a `deptrac` node replicating the `adr_kit` shape (plugins/tooling group, `ring`/`pos` near the other A6 nodes). Add a matching `nd(...)` / `NODE_DETAILS` entry (Russian, per the file's convention) and a `NODE_META` entry with `since: '17.05.2026'`:
> "deptrac — архитектурный гейт: статический анализ направления зависимостей между слоями (Controller/Service/Model/…), lefthook job 10, baseline на унаследованные нарушения. Декларативно, без LLM (AK6). Закрывает A6-пробелы conformance + границы слоёв + дрейф C4."
Add an edge from `tooling` (or `psr_v1`) to `deptrac`, mirroring the A6 edges.
- [ ] **Step 3: Map the node to section A6**
In `NODE_SECTION` add `deptrac: 'A6',`. Section A6 «Архитектура систем» goes 3 → 4 nodes. Update the group-count comment (plugins/tooling) and the header node/edge metrics (+1 node, +1 edge).
- [ ] **Step 4: Smoke-test the map**
```bash
npx stylelint docs/automation-graph.html
```
Open `docs/automation-graph.html` via a local `http.server` (quirk 90 — `file://` rejected) with Playwright MCP. Verify: 0 JS console errors (favicon 404 is harmless); `NODES.length` increased by 1; the `deptrac` node renders; clicking section A6 highlights 4 nodes.
- [ ] **Step 5: Commit**
```bash
git add docs/automation-graph.html
git commit -m "feat(map): deptrac node — extends section A6 to 4 nodes"
```
---
## Task 9: Final regression & branch finish
**Files:** none modified.
- [ ] **Step 1: Full pre-commit chain**
```bash
npx lefthook run pre-commit
```
Expected: all **10** jobs green (job 10 `deptrac` = 0 violations, baseline applied).
- [ ] **Step 2: Confirm app runtime code untouched — run the suites**
This epic adds only `deptrac.yaml` + a composer dev-dep + docs; it changes **no** `app/` runtime code:
```bash
cd app && composer test:parallel
npm run test:vue
```
Expected: Pest and Vitest counts **identical** to the Task 1 Step 2 baseline (0 regressions). Record exact counts; write out any failure with file:line.
- [ ] **Step 3: Confirm the hook chain is intact**
Compare `.claude/settings.json` + `~/.claude/settings.json` to the Task 1 Step 3 snapshot — unchanged. The economy marker still appears; the Stop verifier still runs. deptrac leaked no lifecycle hook.
- [ ] **Step 4: Pre-push checks**
```bash
./bin/gitleaks.exe detect --source . --no-banner --config .gitleaks.toml --redact
./bin/lychee.exe --config .lychee.toml "docs/**/*.md" "*.md"
```
Expected: gitleaks 0 leaks; lychee 0 broken (new `docs/architecture/c4-component-layers.md` + `docs/adr/ADR-005-*.md` are scanned — fix or `.lychee.toml`-exclude any link).
- [ ] **Step 5: Finish the branch**
Invoke `superpowers:finishing-a-development-branch` — present the standard options. Do **not** push without an explicit user choice. Push pattern: `git push origin feat/deptrac-architecture-fitness:main`.
---
## Self-Review
**1. Spec coverage (the 4 A6 gaps).** Gap «conformance / fitness» + gap «направление зависимостей / границ слоёв» → Tasks 3-5 (deptrac.yaml ruleset + baseline + lefthook job 10, red-green-proven). Gap «дрейф C4 vs код» → Task 6 (code-derived component diagram; context-level explicitly carried to a §8 checklist line — Task 7 Step 5 via the §6 paragraph / acknowledged out-of-tooling). Gap «активное проектирование архитектуры фичи» → **deliberately not a tool**: it is covered by the existing cross-cutting `brainstorming`/`writing-plans`/SPARC-architect + architecture-patterns #38, and ADR-005 (Task 3) records the layer model that design work now references — closing the gap by wiring, not by an install (per the agreed analysis; a 4th overlapping design agent would violate §5 п.6). Conflict audit: DT1→T2, DT2→T5.2, DT3→T4, DT4/DT5→T7.2, DT6→T3.1, DT7→(no task — no lint conflict), DT8→T2, DT-NUM→T1/T7.1. No gaps.
**2. Placeholder scan.** `#N` (Task 7) and the deptrac package version / collector syntax / formatter list (Task 3, Task 6) are **runtime-resolved by design** — Task 1 Steps 4-5 carry concrete resolution criteria (same pattern as the A6/D3/C9 plans). The `deptrac.yaml`, `lefthook.yml` job 10, and ADR-005 contents are shown in full. No "TBD" / "handle edge cases".
**3. Consistency.** Branch `feat/deptrac-architecture-fitness` consistent T1↔T9. Node id `deptrac` consistent T8 Steps 2-3. Category **architecture-tooling** consistent T7 Steps 2-4. Paths consistent: `app/deptrac.yaml`, `app/deptrac.baseline.yaml`, `docs/architecture/c4-component-layers.md`, `docs/adr/ADR-005-*.md`. The DT1 primary/fallback fork (composer dep vs `bin/deptrac.phar`) is flagged uniformly (T2, T5.1 `run:` line, T7.2). lefthook job count 9 → 10 consistent T5↔T9.
---
## Execution Handoff
Plan complete and saved to `docs/superpowers/plans/2026-05-17-deptrac-architecture-fitness-integration.md`.
**Sequencing decision required before execution** (see the "Sequencing" header): this epic runs **after D3**. Its slot relative to **C9** is the user's call — `… → D3 → deptrac → C9` or `… → D3 → C9 → deptrac`. Both are valid.
**Execution method:**
1. **Subagent-Driven (recommended)** — fresh subagent per task, two-stage review. *Caveat:* Task 1 Step 4-5 (WebFetch), Task 7 Step 5 (`claude-md-management`), Task 8 Step 4 (Playwright smoke) are main-session-bound — those steps stay with the controller.
2. **Inline Execution** — `superpowers:executing-plans`, batch with checkpoints (same as the A6/D3/C9 plans — install/config/docs-heavy with interactive steps).