fix(metrics): make TurboMQ the sum of cluster factors (not the mean)#26
Conversation
Architecture Drift ReportAlgorithm: PKG | Entities: 673 | Components: 7 Drift from Baseline
Changes
Smells (1)
Generated by arcade-agent |
🤖 Architecture Analysis SummaryPowered by arcade-agent — automatic architectural self-analysis 📈 Metric EvolutionBaseline commit: Legend: 🟢 better · 🔴 worse · 🟡 low impact · ⚪ no change
🏛️ Current Architecture
🧭 Principle Signals
🎯 Score DriversBiggest risks
Strongest areas
🕸️ High-Level Designgraph TD
Algorithms["Algorithms\n39 entities\n5 classes / 3 methods"]
Budget["Budget\n3 entities\n0 classes / 0 methods"]
Cache["Cache\n4 entities\n0 classes / 0 methods"]
Ci["Ci\n5 entities\n0 classes / 0 methods"]
Exporters["Exporters\n14 entities\n1 classes / 0 methods"]
Incremental["Incremental\n2 entities\n1 classes / 2 methods"]
Parsers["Parsers\n17 entities\n11 classes / 27 methods"]
Serialization["Serialization\n8 entities\n0 classes / 0 methods"]
Tools["Tools\n23 entities\n4 classes / 2 methods"]
Cache --> Serialization
Ci --> Algorithms
Ci --> Exporters
Ci --> Serialization
Ci --> Tools
Serialization --> Algorithms
Serialization --> Parsers
Tools --> Algorithms
Tools --> Cache
Tools --> Exporters
Tools --> Parsers
🏗️ Components breakdown
🚨 Architectural Smells
📈 Evolution vs BaselineBaseline commit: Architecture-to-Architecture (A2A) Comparison
Component matching detailsMatched:
High-level component statistics
Before/After Mermaid diagramsBaseline graph TD
Algorithms["Algorithms\n39 entities\n5 classes / 3 methods"]
Budget["Budget\n3 entities\n0 classes / 0 methods"]
Cache["Cache\n4 entities\n0 classes / 0 methods"]
Ci["Ci\n5 entities\n0 classes / 0 methods"]
Exporters["Exporters\n14 entities\n1 classes / 0 methods"]
Incremental["Incremental\n2 entities\n1 classes / 2 methods"]
Parsers["Parsers\n17 entities\n11 classes / 27 methods"]
Serialization["Serialization\n8 entities\n0 classes / 0 methods"]
Tools["Tools\n23 entities\n4 classes / 2 methods"]
Cache --> Serialization
Ci --> Algorithms
Ci --> Exporters
Ci --> Serialization
Ci --> Tools
Serialization --> Algorithms
Serialization --> Parsers
Tools --> Algorithms
Tools --> Cache
Tools --> Exporters
Tools --> Parsers
Current graph TD
Algorithms["Algorithms\n39 entities\n5 classes / 3 methods"]
Budget["Budget\n3 entities\n0 classes / 0 methods"]
Cache["Cache\n4 entities\n0 classes / 0 methods"]
Ci["Ci\n5 entities\n0 classes / 0 methods"]
Exporters["Exporters\n14 entities\n1 classes / 0 methods"]
Incremental["Incremental\n2 entities\n1 classes / 2 methods"]
Parsers["Parsers\n17 entities\n11 classes / 27 methods"]
Serialization["Serialization\n8 entities\n0 classes / 0 methods"]
Tools["Tools\n23 entities\n4 classes / 2 methods"]
Cache --> Serialization
Ci --> Algorithms
Ci --> Exporters
Ci --> Serialization
Ci --> Tools
Serialization --> Algorithms
Serialization --> Parsers
Tools --> Algorithms
Tools --> Cache
Tools --> Exporters
Tools --> Parsers
Component dependency delta
💡 CI/CD Insights
📄 View HTML reports and artifacts This comment is auto-generated by the self-dogfooding CI job. It updates on every push to this PR. |
|
Split out the unrelated commit: the Consequence for this PR's CI: it will go red again until #28 merges, with 4 failures in |
TurboMQ's docstring described the Bunch-style sum of per-component cluster factors, but the body returned the mean (sum / k), which is algebraically identical to BasicMQ. The two metrics therefore always reported the same number, presenting one signal as two. Return the raw sum per Mitchell & Mancoridis, keep BasicMQ as the normalized mean, and expose `normalized` / `num_components` in TurboMQ's details. Derived balanced scores consume the normalized form so they stay bounded to [0, 1] and their values are unchanged. Closes #25 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Closes #25
Root cause
compute_turbo_mqdocumented TurboMQ as the sum of per-component cluster factors but returnedturbo_mq / num_components. Since BasicMQ's per-component termintra/(intra + 0.5·inter)is algebraically the same cluster factor as TurboMQ's2·intra/(2·intra + inter), the mean made the two metrics identical for every input — one signal reported as two.Formula change
Σ CF(i)(Mitchell & Mancoridis / Bunch), so its range is[0, k]forkcomponents.detailsgainsnormalized(sum / k) andnum_components;raw_sumis kept for backward compatibility.TurboMQ / k, in[0, 1].compute_balanced_scoresnow reads TurboMQ's normalized value forcohesion_family, so every derived score stays bounded to[0, 1]and its numeric value is unchanged.Docs touched in-repo:
compute_metricstool docstring, README "Balanced Architecture Score" section, and.github/skills/improve-architecture-metrics/SKILL.md(TurboMQ is no longer comparable across differing component counts — use BasicMQ for that).Tests
Regression test added first (confirmed red on the old code, green after):
test_turbo_mq_is_the_sum_of_cluster_factors— value equals the sum ofdetails["cluster_factors"]; fixture arithmetic pinned (CalcCF = 0.5,UtilCF = 0.0 → 0.5, where the mean would be 0.25).test_turbo_mq_and_basic_mq_are_not_identical— on the k = 2 fixture,TurboMQ != BasicMQandTurboMQ == k * BasicMQ.test_turbo_mqbound relaxed from[0, 1]to[0, k].pytest: 231 passed, 13 skipped. The 4 failures intests/test_github_action_distribution.pyare pre-existing onmainand unrelated — they assert the workflow/README pin the current package version, which was not propagated in thev0.2.0release commit (8090d12).ruff check src/ tests/: clean.mypy src/arcade_agent/algorithms/coupling.py: the only 2 errors are the pre-existing_score_driversdict-item errors, unchanged by this PR.Changed baseline / report values
.arcade/baseline.jsonstores architecture only (components/rationale), no metric values — it is unchanged by this PR, and thearch-driftworkflow regenerates it on push tomainanyway.Self-analysis of this repo (
arcade-agent.ci.run_self_analysis --algorithm pkg --filter-non-architectural-helpers, k = 9 components), before → after:TurboMQ is the only value that moves; it moves by exactly ×k. The first PR self-analysis comment after this merges will show a large one-off TurboMQ jump against the stored baseline artifact — that is the rescale, not an architectural change.
The committed sample reports
examples/arcade_core_report.htmlandexamples/comparison_report.htmlembed a pre-fix TurboMQ (0.291) from an external project run. They are static illustrations, are not asserted by any test, and cannot be regenerated here (source project not available), so they are left as-is.Follow-up (do not do in this PR)
The live docs site arcade-agent.dev (repo
lemduc/arcade-agent-site, pagedocs/reference/metrics) currently documents the TurboMQ ≡ BasicMQ equivalence as intended behavior — accurate before this change, wrong after. It must be updated after this PR merges. That repo is deliberately untouched here.🤖 Generated with Claude Code