| name | arch-fitness-review |
| description | Use when reviewing a GitHub pull request for architectural impact — computes cyclomatic complexity, coupling/instability, main-sequence distance, cycles, boundary violations, cohesion (LCOM4), conascence, duplication, hotspots, and blast radius as a before/after delta, then posts a Mermaid report on the PR. Triggers on "arch review", "architecture review", "review the architecture of PR", "fitness review". |
Architecture Fitness Review
Measure the structural impact of a PR and post an actionable report. You surface
signals; a human decides. Never say code is "wrong"; say the PR "increased risk here".
1. Prerequisites
gh authenticated, run from inside the target repo (or pass --repo <dir>).
- Analyzer deps installed once:
cd <skill>/analyzer && npm install.
2. Run the analysis
node <skill>/scripts/run-pr.mjs <PR-number-or-URL>
This prints the path to delta.json. Read it. The file is shaped { pr, baseRefName, headRefName, changed, config, delta: { … } }. All metric fields referenced below live inside that inner delta object (e.g. delta.cycles.new, delta.semanticDupShortlist). The risk thresholds live under config (resolved from the head branch's arch-fitness.config.json, merged with defaults), e.g. config.thresholds.maxCyclomaticComplexity, config.mainSequence.failDistanceAbove, config.coupling.warnInstabilityIncreaseAbove — not global constants. If the repo has no analyzable TS/JS in
the diff, tell the user "nothing to analyze" and stop — do not post.
3. Interpret the LLM layer (over delta.json, not the raw repo)
- Semantic duplication: for each
delta.semanticDupShortlist entry, compare the new
function against its candidates by signature/intent. Only report a pair if they
plausibly implement the same logic. Hedge ("may duplicate").
- Conascence: from
delta.conascence, keep only candidates that look load-bearing (a
status/enum string duplicated across modules; a high-arity positional signature).
- Cohesion: narrate
delta.cohesion.worsened — a class gaining an unrelated component
may be taking on a second responsibility. Ask, don't assert.
4. Compute risk level
- High if: any new cycle in
delta.cycles, any new boundary violation in delta.boundaryViolations, or a CC crossing
config.thresholds.maxCyclomaticComplexity by >50%, or any delta.mainSequence.modules[].distance above config.mainSequence.failDistanceAbove.
- Medium if: any CC increase in
delta.complexity, delta.coupling.instabilityIncreased above config.coupling.warnInstabilityIncreaseAbove,
delta.cohesion worsened, or new duplication in delta.duplication.
- Low otherwise.
5. Render the report (Markdown + Mermaid)
Sections, in order: Summary · Risk level · Architectural delta (table: metric,
before → after, note) · Main sequence (table: module from delta.mainSequence.modules, A, I, D, zone) · Dependency
graph (Mermaid; mark NEW cycles/violations from delta.cycles.new and delta.boundaryViolations.new in red) · Reviewer questions.
Zones: near line = healthy; low A + low I = zone of pain; high A + high I =
zone of uselessness.
Mermaid graph example (build edges from delta.mainSequence.modules + highlight
delta.cycles.new / delta.boundaryViolations.new):
graph LR
orders --> billing
billing --> notifications
notifications -.->|NEW CYCLE| orders
classDef bad stroke:#e5484d,stroke-width:2px;
class orders,billing,notifications bad;
Reviewer questions are concrete and specific to the findings, e.g.:
OrderProcessor.process() went CC 7 → 16 — should it be split?
- New cycle
orders → billing → notifications → orders — invert via an event?
calculateTotalPrice may duplicate PricingService.computeTotal — intended?
6. Upsert the PR comment (do not spam)
Every comment starts with the hidden marker <!-- arch-fitness -->.
gh api repos/{owner}/{repo}/issues/<PR>/comments --jq '.[] | select(.body | startswith("<!-- arch-fitness -->")) | .id'
- If an id is returned:
gh api --method PATCH repos/{owner}/{repo}/issues/comments/<id> -f body=@report.md
- Else:
gh pr comment <PR> --body-file report.md
Write the report to a temp file whose first line is <!-- arch-fitness -->.