From 9743c35e5ee82746899ea44570408e9ae2172046 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivett=20=C3=96rd=C3=B6g?= Date: Wed, 29 Jul 2026 16:50:52 +0200 Subject: [PATCH] Add Surface Change Attractors pattern Co-Authored-By: Claude Opus 5 --- .../patterns/surface-change-attractors.md | 27 +++++++++++++++++++ documents/relationships.mmd | 3 +++ 2 files changed, 30 insertions(+) create mode 100644 documents/patterns/surface-change-attractors.md diff --git a/documents/patterns/surface-change-attractors.md b/documents/patterns/surface-change-attractors.md new file mode 100644 index 0000000..7fba0ed --- /dev/null +++ b/documents/patterns/surface-change-attractors.md @@ -0,0 +1,27 @@ +--- +authors: [ivett_ordog] +alternative_titles: ["Hotspot Analysis"] +--- + +# Surface Change Attractors + +## Problem +Architectural problems hide as churn. Some files attract every change; some files always change together even though the module structure claims they're independent. Humans normalize this friction. Agents suffer it too: hot files get re-read into context constantly, and edits concentrate exactly where the conflicts and bugs live. None of this is visible by reading the code — the structure looks fine; only the history shows the problem. + +## Pattern +Mine version control for behavioral signals (Adam Tornhill-style analysis): + +- **Hotspots**: change frequency × complexity — files that are both churned and complicated +- **Change coupling**: files that repeatedly change in the same commits despite no visible dependency + +Then hand the findings to the agent as design constraints, not just data: + +- "These five files change together in most commits — propose a redesign that lets them change independently" +- "This file is touched by every feature — split it along its reasons to change" + +Refactor incrementally toward the proposed design. + +Canary in the Code Mine reads the AI's live struggle as the quality signal; Surface Change Attractors finds the same signal in your version history — before the struggle happens. + +## Example +A script over `git log` counts per-file commit frequency and co-change pairs (code-maat and CodeScene do this out of the box — or Offload Deterministic: have the agent write the script). The top attractor is a 900-line "service" touched in 70% of commits, co-changing with a validator and a serializer in two other modules. Given those constraints, the agent proposes moving validation and serialization behind the service's interface. After the refactor, features stop fanning out across three modules. diff --git a/documents/relationships.mmd b/documents/relationships.mmd index b4046f6..38d038a 100644 --- a/documents/relationships.mmd +++ b/documents/relationships.mmd @@ -10,6 +10,9 @@ graph LR patterns/active-partner -->|solves| obstacles/obedient-contractor patterns/canary-in-the-code-mine -->|solves| obstacles/degrades-under-complexity patterns/canary-in-the-code-mine -->|solves| obstacles/context-rot + patterns/surface-change-attractors -->|solves| obstacles/degrades-under-complexity + patterns/surface-change-attractors <-->|similar| patterns/canary-in-the-code-mine + patterns/surface-change-attractors -->|uses| patterns/offload-deterministic patterns/chain-of-small-steps -->|solves| obstacles/degrades-under-complexity patterns/chain-of-small-steps -->|solves| obstacles/limited-focus patterns/check-alignment -->|solves| anti-patterns/silent-misalignment