feat(ci): enrich architecture drift report with actionable details - #30
Merged
Conversation
The drift report posted on PRs was too sparse to be actionable: - All baseline metric columns showed '—' (metrics never persisted) - Entity movements were a bare count with no details - No component breakdown, no diagram, no smell guidance Changes: 1. Baseline now persists metrics alongside architecture (backwards compatible — old baselines without metrics still load fine). 2. Metric table shows real Baseline→Current deltas with direction indicators (🟢 improved / �� degraded / ⚪ unchanged). 3. Entity movements list top-15 individual moves (entity → component). 4. Component breakdown table (name, entity count, responsibility). 5. Mermaid component dependency diagram for visual orientation. 6. Smell entries include actionable 💡 recommendations. Breaking change: load_architecture() now returns (Architecture, dict) tuple. All callers updated.
Contributor
Architecture Drift ReportAlgorithm: PKG | Entities: 673 | Components: 7 Drift from Baseline
Changes
Components
Architecture Diagramgraph LR
Scripts["Scripts"]
ArcadeAgent["ArcadeAgent"]
Tests["Tests"]
Fixtures["Fixtures"]
TestAlgorithms["TestAlgorithms"]
TestParsers["TestParsers"]
TestTools["TestTools"]
Scripts --> ArcadeAgent
Scripts --> Fixtures
Tests --> ArcadeAgent
Tests --> Fixtures
Smells (1)
Generated by arcade-agent |
Contributor
🤖 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. |
Previously the detailed '🤖 Architecture Analysis Summary' comment (metric evolution, principle signals, score drivers, Mermaid diagram, A2A comparison) only appeared on PRs targeting main because ci.yml had 'pull_request: branches: [main]'. PRs targeting feature branches (e.g. codex/rust-parser) only got the sparse arch-drift.yml comment. Remove the branch filter so every PR receives the full analysis. The baseline artifact is still sourced from the last successful main push, so comparisons remain meaningful.
lemduc
added a commit
that referenced
this pull request
Jul 28, 2026
Resolves a semantic collision, not just a textual one: #30 independently enriched the same PR comment this branch rewrote. Conflicts and how they were resolved: - ci/arch_diff.py "### Changes" block. #30 rebuilt it with entity-movement detail, but it reads summary["possible_splits"]/["possible_merges"] -- keys this branch removes -- and derives added/removed names from the Hungarian `matches` list, which cannot represent a split or a merge and is the split-brain this branch's own review made us fix in compare_baseline. The changelog block supersedes it: same three facts (components added/removed, entity movements, splits/merges), from entity provenance, and it names the source component of each movement rather than only its destination. - ci/arch_diff.py smells section. Kept #30's actionable recommendations, routed through the consolidated display_value helper rather than the duplicate _display_value this branch removed. - tests/test_arch_diff.py. Purely additive on both sides; kept both. Two follow-on changes the merge required: - #30 now persists metrics in the baseline and renders a metric table with real baseline->current deltas. That falsifies this branch's rationale for metrics_a=[] and would have produced two metric tables in one comment, so render_changelog_markdown gains include_metrics (default True) and arch_diff passes False -- mirroring the existing include_smells decision. The metric deltas stay in the changelog dict for MCP callers. - #30's current-state inventory table is "### Components"; the changelog's delta list was also "Components", landing adjacent at a different level. Renamed the changelog's to "Component changes", which is what it actually lists. load_architecture() -> tuple (from #30) auto-merged into this branch's call sites. Dead _MAX_ENTITY_MOVEMENTS removed with its only consumer. Tests pin both merge decisions: the changelog must not render a second metric or smells section, and the superseded "### Changes" block must not reappear. pytest 405 passed; ruff clean; mypy 218 (unchanged from this branch). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The Architecture Drift Report posted on PRs (e.g. #29 comment) was too sparse to be actionable:
—— metrics were never persisted inbaseline.json, so no delta could ever be computedcodex/rust-parser) never got the rich "🤖 Architecture Analysis Summary" becauseci.ymlhadpull_request: branches: [main]Solution
1. Baseline persists metrics (backwards compatible)
save_architecture()now accepts an optionalmetricsdict.load_architecture()returns(Architecture, dict[str, float]). Old baselines without metrics still load fine (empty dict).Once
--update-baselineruns with this code, all future PR reports will show real deltas with direction indicators:2. Entity movement details
Top-15 individual entity movements listed as
entity → Component, with "… and N more" overflow.3. Component breakdown table
4. Mermaid component dependency diagram
5. Actionable smell recommendations
Each smell now includes a 💡 recommendation (split component, break cycle, reduce fan-in, stabilize interface).
6. Self-dogfooding runs on ALL PRs
Removed
branches: [main]filter fromci.yml'spull_requesttrigger. Now every PR (including those targeting feature branches) receives the full "🤖 Architecture Analysis Summary" with metric evolution, principle signals, score drivers, Mermaid diagram, and A2A comparison. Baseline is still sourced from the last successfulmainpush.Breaking change
load_architecture()signature changed from-> Architectureto-> tuple[Architecture, dict[str, float]]. All internal callers updated.Validation