Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 39 additions & 39 deletions docs/metrics/code-health-baseline.json
Original file line number Diff line number Diff line change
@@ -1,60 +1,60 @@
{
"last_run": "2026-09-21",
"commit_sha": "0c470c76",
"last_run": "2026-09-28",
"commit_sha": "ebc2bfb4",
"hotspot_top3": [
{
"file": "src/backend/client_portal/service.py",
"churn": 56,
"complexity": 169,
"score": 9464
"file": "src/backend/services/task_execution_service.py",
"churn": 35,
"complexity": 331,
"score": 11585
},
{
"file": "src/backend/services/agent_service/crud.py",
"churn": 38,
"complexity": 154,
"score": 5852
"file": "src/backend/client_portal/service.py",
"churn": 58,
"complexity": 171,
"score": 9918
},
{
"file": "src/backend/services/task_execution_service.py",
"churn": 33,
"complexity": 154,
"score": 5082
"file": "src/backend/services/operator_queue_service.py",
"churn": 22,
"complexity": 427,
"score": 9394
}
],
"hotspot_scores": {
"src/backend/client_portal/service.py": 9464,
"src/backend/services/agent_service/crud.py": 5852,
"src/backend/services/task_execution_service.py": 5082,
"src/backend/services/cleanup_service.py": 4575,
"src/backend/services/agent_service/lifecycle.py": 4110,
"src/backend/services/skill_service.py": 3944,
"src/backend/services/system_service.py": 3383,
"src/backend/routers/agents.py": 2825,
"src/backend/services/chat_execution_service.py": 2394,
"src/backend/services/task_execution_service.py": 11585,
"src/backend/client_portal/service.py": 9918,
"src/backend/services/operator_queue_service.py": 9394,
"src/backend/services/cleanup_service.py": 6214,
"src/backend/services/agent_service/crud.py": 6160,
"src/backend/services/agent_service/lifecycle.py": 5280,
"src/backend/services/skill_service.py": 4410,
"src/backend/services/system_service.py": 3636,
"src/backend/services/chat_execution_service.py": 3151,
"src/backend/routers/agents.py": 2756,
"src/backend/services/canary_alerts.py": 2728,
"src/backend/services/template_service.py": 1788,
"src/backend/services/operator_queue_service.py": 1710,
"src/backend/services/canary_alerts.py": 1392,
"src/backend/database.py": 1248,
"src/backend/db/schedules/analytics.py": 1674,
"src/backend/database.py": 1440,
"src/backend/canary/snapshot.py": 1125,
"src/backend/main.py": 975,
"src/backend/services/compatibility/static_checks.py": 1080,
"src/backend/main.py": 1050,
"src/backend/services/platform_prompt_service.py": 1040,
"src/backend/db/schedules/stats.py": 960,
"src/backend/dependencies.py": 855,
"src/backend/adapters/message_router.py": 940,
"src/backend/dependencies.py": 912,
"src/backend/services/agent_service/deploy.py": 832,
"src/backend/services/gemini_voice.py": 798,
"src/backend/services/platform_prompt_service.py": 784,
"src/backend/db/schedules/analytics.py": 721,
"src/backend/services/compatibility/static_checks.py": 710,
"src/backend/routers/ops.py": 689,
"src/backend/db/schedules/executions.py": 756,
"src/backend/adapters/telegram_adapter.py": 752,
"src/backend/db/operator_queue.py": 686,
"src/backend/shared_sessions/service.py": 680,
"src/backend/utils/url_validation.py": 670,
"src/backend/adapters/message_router.py": 664,
"src/backend/db/schedules/executions.py": 656,
"src/backend/adapters/telegram_adapter.py": 616,
"src/backend/db/operator_queue.py": 576,
"src/backend/adapters/whatsapp_adapter.py": 525
"src/backend/services/pull_coordination_service.py": 648,
"src/backend/routers/ops.py": 636
},
"size_violations_count": 64,
"size_violations_count": 70,
"stale_todo_count": 6,
"high_coupling_count": 12,
"high_coupling_count": 14,
"circular_import_count": 0
}
173 changes: 87 additions & 86 deletions docs/metrics/code-health-latest.md
Original file line number Diff line number Diff line change
@@ -1,127 +1,128 @@
# Code Health Report — 2026-09-21 (`0c470c76`)
# Code Health Report — 2026-09-28 (`ebc2bfb4`)

> Dashboard committed by `/code-health` (dashboard-only — no GitHub issues; `/groom`'s
> Debt Health section converts findings). Previous baseline: 2026-09-07 (`c9074cd9`).

**Data-integrity note:** the local checkout this scan started from was 156 commits
behind `origin/dev` (last synced around `c9074cd9`, missing two weeks of history). In
that gap, three local-only dashboard commits (dated 2026-09-08, 2026-09-14, 2026-09-21)
had been produced against the increasingly stale history and never reached `origin` —
`dev` is a GitHub-protected branch, so a plain `git commit` there cannot be pushed
directly, and those runs stopped short of the branch+PR step (see
`chore/code-health-dashboard-2026-09-07`, #2560, for the last run that did land). A
stray uncommitted `workspace_delivery` schedule feature (abilityai/trinity-enterprise#498,
unrelated to this scan, not yet upstream) plus a platform-managed `CLAUDE.md` skills
section were stashed rather than discarded, a fresh branch was cut from the
`origin/dev` tip, and the full scan was re-run from scratch before writing anything —
the same recovery the 2026-09-07 report used. The numbers below are a real 14-day
comparison against the actual `origin/dev` tree; the three orphaned local-only commits
were left untouched on the stale local `dev` branch (out of scope for this run).
> Debt Health section converts findings). Previous baseline: 2026-09-21 (`0c470c76`).

## Executive Summary

| Metric | Value | Trend vs 2026-09-07 |
| Metric | Value | Trend vs 2026-09-21 |
|--------|-------|-------|
| Top hotspot score | 9464 (`client_portal/service.py`) | ↑ |
| Files > 800 lines | 64 | → |
| Top hotspot score | 11585 (`task_execution_service.py`) | ↑ |
| Files > 800 lines | 70 | → |
| Stale TODO/FIXME/HACK | 6 | → |
| High fan-out files (>20 imports) | 12 | → |
| High fan-out files (>20 imports) | 14 | ↑ |
| Circular imports | 0 | → |

The headline move is the hotspot ranking flipping at #1: `client_portal/service.py`
overtook `agent_service/crud.py`, which had held #1 for at least two consecutive runs,
with a 72% higher score (9464 vs 5508 two weeks ago) — churn nearly doubled (37→56
touches in the trailing 90-day window) against a smaller complexity increase
(139→169). Every other tracked metric held inside the ±10% noise band.
`routers/settings.py` — the #3 hotspot two weeks ago at 4805, and flagged in the last
two reports as a split candidate — dropped out of the ranking entirely: it was split
into a `routers/settings/` package (11 files, largest 901 lines) sometime in the last
two weeks, exactly the refactor suggested; no successor file scores high enough
individually to re-enter the top ranks.
The headline move is the hotspot ranking flipping at #1 again: `task_execution_service.py`
overtook `client_portal/service.py`, which had held #1 for at least two consecutive runs,
with a 22% higher score (11585 vs 9464 last week) — churn held flat (33→35 touches) but
complexity more than doubled (154→331), driven almost entirely by one landed feature:
`f6dfb000` ("ask endings — one sink, endings ledger, person-only endings, wake on any
ending, self-readback") touched both `task_execution_service.py` and
`operator_queue_service.py` in the same PR. `operator_queue_service.py` shows the same
signature even more sharply — complexity roughly quintupled off a low prior base while
churn stayed modest (22 touches) — and vaults straight to #3 this run; it did not
appear in last week's top-30 hotspot map at all. `client_portal/service.py` itself is
not flat either: churn rose again (56→58) and complexity ticked up (169→171), but it was
simply outpaced. High fan-out crossed the 12→14 files threshold (↑) on the back of the
same feature landing new cross-cutting imports in `operator_queue_service.py`,
`agent_service/lifecycle.py`, and `a2a.py`. Files > 800 lines rose 64→70, just inside
the ±10% noise band (70.4 would have tripped it). Stale TODOs and circular imports are
unchanged.

## Top 5 Hotspots (churn 90d × complexity — highest refactoring ROI)

| Rank | File | Churn (90d) | CC Score | Hotspot Score | Lines |
|------|------|-------------|----------|---------------|-------|
| 1 | `src/backend/client_portal/service.py` | 56 | 169 | 9464 | 5622 |
| 2 | `src/backend/services/agent_service/crud.py` | 38 | 154 | 5852 | 3277 |
| 3 | `src/backend/services/task_execution_service.py` | 33 | 154 | 5082 | 3043 |
| 4 | `src/backend/services/cleanup_service.py` | 25 | 183 | 4575 | 3008 |
| 5 | `src/backend/services/agent_service/lifecycle.py` | 30 | 137 | 4110 | 1713 |

**Interpretation**: `client_portal/service.py` is now both the largest file in
`src/backend/` (5622 lines) and the top hotspot by a wide margin, continuing the trend
the 2026-09-07 report already called out as "the most actionable finding" — it has
grown another ~1700 lines and gained 19 more touches in two weeks and has still not
been evaluated for a package-style split. `agent_service/crud.py` and
`task_execution_service.py` hold materially unchanged churn/complexity from last run
(rank #1→#2 and #5→#3 respectively, reordered only because of `service.py`'s jump and
`settings.py`'s exit). `cleanup_service.py` and `agent_service/lifecycle.py` round out
the top 5, both essentially flat vs. 2026-09-07.
| 1 | `src/backend/services/task_execution_service.py` | 35 | 331 | 11585 | 3062 |
| 2 | `src/backend/client_portal/service.py` | 58 | 171 | 9918 | 5663 |
| 3 | `src/backend/services/operator_queue_service.py` | 22 | 427 | 9394 | 1992 |
| 4 | `src/backend/services/cleanup_service.py` | 26 | 239 | 6214 | 3459 |
| 5 | `src/backend/services/agent_service/crud.py` | 40 | 154 | 6160 | 3389 |

**Interpretation**: The top 3 hotspots this run share one root cause — the `ask endings`
feature (abilityai/trinity-enterprise#611, PR A of 2) landed complex new logic across the
operator-queue / execution seam in a single week. `task_execution_service.py` is now both
the top hotspot and squarely inside the CAS-discipline invariant called out in
`architecture.md` (every terminal side effect must win the status CAS and close its own
dispatch activity — the #1804/#767/#45 recurring bug class); adding complexity here is the
highest-risk place in the codebase for that class to recur. `operator_queue_service.py`
entering the top 3 from outside the top-30 in one run is the most actionable signal this
week: complexity moved from a low base to 427 (the single highest CC score of any file
scanned, ahead of even `client_portal/service.py`) while the file itself is comparatively
small (1992 lines) — density, not sprawl, is the concern. `cleanup_service.py` and
`agent_service/crud.py` are essentially unchanged from last week (both flagged in prior
reports; `crud.py`'s deferred #1028 phase-helper extraction remains unactioned), reordered
only by the two risers above them.

## Top 3 Size Violations

| File | Lines | Threshold Exceeded | Suggested Action |
|------|----|------|---------|
| `src/backend/client_portal/service.py` | 5622 | critical (>800) | Extract service layer — also the #1 hotspot this run, the single highest-ROI split candidate; `client_portal/` already has `router.py`/`db.py`/`models.py`/`schema.py`/`agent_page.py` siblings, so split by portal-session vs. portal-agent-roster concerns (Invariant #1, Three-Layer pattern, more strictly at the service tier) |
| `src/backend/models.py` | 4559 | critical (>800) | Centralized Pydantic models (Invariant #14) — size is the accepted cost of "one place for the API contract," not a split candidate |
| `src/backend/db/migrations.py` | 4429 | critical (>800) | Append-only versioned migration log by design (Invariant #3) — grows monotonically; expected growth, not a refactor candidate |
| `src/backend/client_portal/service.py` | 5663 | critical (>800) | Extract service layer — flagged in the last two reports as the top split candidate; `client_portal/` already has `router.py`/`db.py`/`models.py`/`schema.py`/`agent_page.py` siblings, so split by portal-session vs. portal-agent-roster concerns (Invariant #1, Three-Layer pattern, more strictly at the service tier). Still not evaluated. |
| `src/backend/db/migrations.py` | 4980 | critical (>800) | Append-only versioned migration log by design (Invariant #3) — grows monotonically; expected growth, not a refactor candidate |
| `src/backend/models.py` | 4969 | critical (>800) | Centralized Pydantic models (Invariant #14) — size is the accepted cost of "one place for the API contract," not a split candidate |

## Top 3 Coupling Issues

| File | Import Count | Issue |
|------|-------------|-------|
| `src/backend/main.py` | 126 | Router-mounting hub (Invariant #4) — mounts ~72 routers plus lifespan phase helpers; expected for its role, not a split candidate |
| `src/backend/database.py` | 55 | Facade importing its composed domain-operation mixins (Invariant #1/#2) — expected shape, not a coupling defect |
| `src/backend/services/agent_service/crud.py` | 37 | Also the #2 hotspot — this one *is* a genuine coupling concern layered on top of size and complexity |
| `src/backend/main.py` | 130 | Router-mounting hub (Invariant #4) — mounts routers plus lifespan phase helpers; expected for its role, not a split candidate |
| `src/backend/database.py` | 61 | Facade importing its composed domain-operation mixins (Invariant #1/#2) — expected shape, not a coupling defect |
| `src/backend/services/agent_service/crud.py` | 38 | Also the #5 hotspot — this one *is* a genuine coupling concern layered on top of size and complexity |

## Stale Smell Inventory

- **Total TODO/FIXME/HACK markers**: 6 (unchanged since at least 2026-09-07 — same six lines, same files)
- **Total TODO/FIXME/HACK markers**: 6 (unchanged since at least 2026-09-07 — same six lines, same files, now a fourth consecutive stable reading)
- All six are informational stubs, not urgent debt:
- `db/migrations.py:1087` — Slack thread cleanup job (references an external design doc)
- `services/monitoring_service.py:510` — error-rate calculation not yet implemented
- `services/monitoring_service.py:813` + `routers/monitoring.py:349` — `recent_alerts` placeholder (paired stub, same shape, two files)
- `services/monitoring_service.py:813` + `routers/monitoring.py:377` — `recent_alerts` placeholder (paired stub, same shape, two files)
- `routers/ops.py:373` + `routers/ops.py:396` — dedicated alerts table not yet built (paired stub in one file)
- These have now been stable across at least three consecutive weekly runs with no
movement — the underlying alerts-table gap (2 markers in `ops.py`, 1 in
`monitoring.py`, 1 in `monitoring_service.py`) is worth a `/groom` look as a real
ticket rather than four scattered TODOs.
- Stable across at least four consecutive weekly runs with no movement — the underlying
alerts-table gap (2 markers in `ops.py`, 1 in `monitoring.py`, 1 in
`monitoring_service.py`) remains worth a `/groom` look as a real ticket rather than
four scattered TODOs.

## Suggested Refactorings (Top 3 Hotspots)

**1. `client_portal/service.py` (9464, ↑ from rank #2 → #1)**
No architectural note yet marks this file as an accepted-monolith-by-design the way
`models.py`/`migrations.py` are. `client_portal/` already has `router.py`/`db.py`/
`models.py`/`schema.py`/`agent_page.py` siblings; `service.py` growing to 5622 lines
while backing the entire Workspace surface (rosters, sessions, chat dispatch,
briefings, rooms glue, deliverables) is the same pattern flagged last run, now more
pronounced. A natural split mirrors sub-feature boundaries: session/thread management,
roster + briefing resolution, and ratings/deliverables could become sibling modules
under a `client_portal/service/` package, following either the `db/schedules/`
mixin-package precedent or the `services/agent_service/` sub-package precedent.
Estimated reduction: 1500-2000 lines. Supports Invariant #1/#2.

**2. `services/agent_service/crud.py` (5852, ↓ from rank #1 → #2, score essentially flat)**
Per `architecture.md`, `create_agent_internal` is already a thin orchestrator over
private `_*` phase-helpers (#1484); the deferred #1028 follow-up — extracting the
phase helpers into `creation_phases.py` — remains unactioned. Estimated reduction:
1500-2000 lines with the orchestrator itself staying in `crud.py`. Supports
Invariant #1/#2.

**3. `services/task_execution_service.py` (5082, ↑ from rank #5 → #3, unchanged
churn/complexity — reordering only)**
Per the `execution.md` architecture invariant, every terminal side effect here is
gated on winning a status CAS, and each CAS winner must close its own dispatch
activity — the exact discipline behind the #1804/#767/#45 recurring bug class. That
invariant is easiest to keep correct when the CAS-winning branches are small and
few. Consider extracting the dispatch-activity close/duration-recording logic into a
focused helper module, leaving this file as orchestration only.
**1. `services/task_execution_service.py` (11585, ↑ from rank #3 → #1)**
Per the `execution.md` architecture invariant, every terminal side effect here is gated
on winning a status CAS, and each CAS winner must close its own dispatch activity — the
exact discipline behind the #1804/#767/#45 recurring bug class. The newly-added
`apply_result` method alone carries a complexity of 66 (radon), the single most complex
function in the file. Consider extracting the dispatch-activity close/duration-recording
logic and the endings-ledger handling introduced by #3023 into a focused helper module,
leaving `apply_result`/`execute_task` as thin orchestration. Estimated reduction:
800-1200 lines. Supports Invariant #1 (Execution area).

**2. `client_portal/service.py` (9918, ↓ from rank #1 → #2, score essentially flat)**
Unchanged assessment from the last two reports: no architectural note yet marks this file
as an accepted-monolith-by-design the way `models.py`/`migrations.py` are. `client_portal/`
already has `router.py`/`db.py`/`models.py`/`schema.py`/`agent_page.py` siblings; a natural
split mirrors sub-feature boundaries (session/thread management, roster + briefing
resolution, ratings/deliverables) under a `client_portal/service/` package, following
either the `db/schedules/` mixin-package precedent or the `services/agent_service/`
sub-package precedent. Estimated reduction: 1500-2000 lines. Supports Invariant #1/#2.
This is the third consecutive report naming this file as the top or near-top actionable
finding with no split evaluated yet.

**3. `services/operator_queue_service.py` (9394, NEW to top 3 — was outside last week's
top-30 entirely)**
The #611 "ask endings" feature added one sink, an endings ledger, person-only endings,
wake-on-any-ending, and self-readback in a single PR against a file that was previously
mid-table. At 427 CC-score across only 1992 lines, this is now the densest file scanned —
a strong signal that the new logic paths (ledger writes, wake fan-out, readback) are not
yet decomposed into helpers the way the rest of the operator-queue seam is. Given
`operator-queue.md`'s ownership of `db/operator_queue.py` alongside this service, a
first pass should extract the endings-ledger read/write path into its own module before
the next feature lands on top of it. Estimated reduction: 500-800 lines. Supports
Invariant #1.

---
*Methodology: hotspot score = git churn (90d) × cyclomatic complexity, where complexity
sums per-function scores from `radon cc -n C` (grade C/complexity≥6 and worse only),
matching the 2026-09-07 baseline. Size-violation and coupling counts are full
`src/backend/` scans (>800 lines / >20 imports), not top-N windows. The baseline's
`hotspot_scores` map is truncated to the top 30 files by score (472 files scored > 0
`hotspot_scores` map is truncated to the top 30 files by score (489 files scored > 0
overall this run) — treat entries outside that set as unranked, not zero.*
Loading