<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Posts on Mikhail Shogin</title><link>https://mshogin.com/post/</link><description>Recent content in Posts on Mikhail Shogin</description><generator>Hugo -- gohugo.io</generator><language>en</language><copyright>Mikhail Shogin</copyright><lastBuildDate>Tue, 24 Mar 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://mshogin.com/post/index.xml" rel="self" type="application/rss+xml"/><item><title>AI Agent Linter Ecosystem: Quality, Cost and Safety Control</title><link>https://mshogin.com/blog/ai-linter-ecosystem/</link><pubDate>Tue, 24 Mar 2026 00:00:00 +0000</pubDate><guid>https://mshogin.com/blog/ai-linter-ecosystem/</guid><description>&lt;h2 id="the-problem"&gt;The Problem
&lt;/h2&gt;&lt;p&gt;AI agents write code fast, but speed comes at a cost. Literally - tokens cost money. And figuratively - code quality degrades without oversight.&lt;/p&gt;
&lt;p&gt;I hit three problems at once:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Architecture degrades&lt;/strong&gt; - agents write working code that violates layer boundaries, creates circular dependencies and god classes&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Costs grow&lt;/strong&gt; - complex prompts go to Opus at $15/1M tokens when Haiku at $0.80 would suffice&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Content isn&amp;rsquo;t filtered&lt;/strong&gt; - production prompts contain things that shouldn&amp;rsquo;t be there&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Each problem has its own tool. But when the tools work together, they amplify each other.&lt;/p&gt;
&lt;h2 id="the-pipeline"&gt;The Pipeline
&lt;/h2&gt;&lt;p&gt;Every request passes through a chain of linters, each responsible for its domain:&lt;/p&gt;
&lt;div class="mermaid"&gt;
graph LR
A[Prompt] --&gt; B[seclint]
B --&gt;|safe| C[promptlint]
B --&gt;|blocked| X[Reject]
C --&gt;|haiku| D1[Agent: Haiku]
C --&gt;|sonnet| D2[Agent: Sonnet]
C --&gt;|opus| D3[Agent: Opus]
D1 --&gt; E[archlint]
D2 --&gt; E
D3 --&gt; E
E --&gt;|pass| F[costlint]
E --&gt;|fail| C
F --&gt; G[Done]
&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;seclint&lt;/strong&gt; - checks content safety (6+/12+/16+/18+ ratings)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;promptlint&lt;/strong&gt; - scores complexity, picks the model&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Agent&lt;/strong&gt; - executes the task on the selected model&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;archlint&lt;/strong&gt; - validates the result for architecture violations&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;costlint&lt;/strong&gt; - records cost, tracks cache hit rate&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If archlint rejects the result, the task escalates to a more powerful model. costlint records the escalation cost.&lt;/p&gt;
&lt;h2 id="the-tools"&gt;The Tools
&lt;/h2&gt;&lt;h3 id="archlint---architecture-linter"&gt;archlint - Architecture Linter
&lt;/h3&gt;&lt;p&gt;Scans Go projects for structural violations.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;archlint scan --format json ./project/
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;What it finds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Layer violations (handler calls repository directly)&lt;/li&gt;
&lt;li&gt;God classes (&amp;gt;20 methods or &amp;gt;15 dependencies)&lt;/li&gt;
&lt;li&gt;Circular dependencies&lt;/li&gt;
&lt;li&gt;Interface Segregation violations (interfaces &amp;gt;5 methods)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Metrics: fan-out, coupling (Ca/Ce), component and link counts.&lt;/p&gt;
&lt;p&gt;GitHub: &lt;a class="link" href="https://github.com/mshogin/archlint" target="_blank" rel="noopener"
&gt;mshogin/archlint&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="promptlint---complexity-based-router"&gt;promptlint - Complexity-Based Router
&lt;/h3&gt;&lt;p&gt;Scores prompt complexity and picks the model. No LLM, pure metrics, &amp;lt;10ms.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Fix typo in README&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; promptlint analyze --output-model
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# haiku&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Design microservices with CQRS&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; promptlint analyze --output-model
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# opus&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Signals: length, sentence count, domain keywords, action type (fix/create/refactor), code presence.&lt;/p&gt;
&lt;p&gt;Integrates with ccproxy for real Claude Code request routing through a proxy.&lt;/p&gt;
&lt;p&gt;GitHub: &lt;a class="link" href="https://github.com/mikeshogin/promptlint" target="_blank" rel="noopener"
&gt;mikeshogin/promptlint&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="costlint---token-cost-analysis"&gt;costlint - Token Cost Analysis
&lt;/h3&gt;&lt;p&gt;Tracks spending, analyzes caching, runs A/B tests between models.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;costlint report --source telemetry.jsonl
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Cost Report:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Total requests: 342
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; By model:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; opus: 48 requests, ~$12.60
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; sonnet: 195 requests, ~$6.50
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; haiku: 99 requests, ~$0.44
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; With optimal routing: ~$8.20 (savings: 58%)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Cache metrics: hit rate, block reuse, content entropy, Jaccard similarity.
A/B testing: 30/30/40 traffic split, per-group cost and quality metrics.&lt;/p&gt;
&lt;p&gt;GitHub: &lt;a class="link" href="https://github.com/mikeshogin/costlint" target="_blank" rel="noopener"
&gt;mikeshogin/costlint&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="seclint--promptsec---content-filter"&gt;seclint / promptsec - Content Filter
&lt;/h3&gt;&lt;p&gt;Age ratings for prompts: 6+, 12+, 16+, 18+.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Help with math homework&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; seclint rate
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# {&amp;#34;rating&amp;#34;: &amp;#34;6+&amp;#34;, &amp;#34;safe&amp;#34;: true}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Explain SQL injection for security course&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; seclint rate
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# {&amp;#34;rating&amp;#34;: &amp;#34;16+&amp;#34;, &amp;#34;safe&amp;#34;: true, &amp;#34;flags&amp;#34;: [&amp;#34;security_tools&amp;#34;]}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Considers educational context - explaining SQL injection for a security course gets 16+ instead of 18+.&lt;/p&gt;
&lt;p&gt;GitHub: &lt;a class="link" href="https://github.com/mikeshogin/seclint" target="_blank" rel="noopener"
&gt;mikeshogin/seclint&lt;/a&gt; / &lt;a class="link" href="https://github.com/mikeshogin/promptsec" target="_blank" rel="noopener"
&gt;mikeshogin/promptsec&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="shared-principles"&gt;Shared Principles
&lt;/h2&gt;&lt;p&gt;All tools follow the same rules:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Go&lt;/strong&gt; - single stack, single build&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No LLM&lt;/strong&gt; - pure metrics, regex, keyword matching. &amp;lt;10ms per request&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CLI + HTTP&lt;/strong&gt; - each tool works as a command and as a server&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;JSONL telemetry&lt;/strong&gt; - unified log format for analysis&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pipeline-friendly&lt;/strong&gt; - exit codes, stdout, pipes&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="numbers"&gt;Numbers
&lt;/h2&gt;&lt;p&gt;On test workload (342 requests over a week):&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Before&lt;/th&gt;
&lt;th&gt;After&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Token spending&lt;/td&gt;
&lt;td&gt;$19.54&lt;/td&gt;
&lt;td&gt;$8.20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Architecture violations&lt;/td&gt;
&lt;td&gt;63&lt;/td&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Requests to expensive model&lt;/td&gt;
&lt;td&gt;100% opus&lt;/td&gt;
&lt;td&gt;14% opus&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Routing latency&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;&amp;lt;10ms&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;58% cost savings without quality loss - simple tasks go to Haiku, architecture tasks stay on Opus.&lt;/p&gt;
&lt;h2 id="orchestration"&gt;Orchestration
&lt;/h2&gt;&lt;p&gt;The tools work autonomously, but deliver maximum impact together. For orchestration we use &lt;a class="link" href="https://github.com/kgatilin/myhome" target="_blank" rel="noopener"
&gt;myhome&lt;/a&gt; - daemon-based AI agent management with workflow stages and scheduled tasks.&lt;/p&gt;
&lt;p&gt;The stack:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;myhome launches agents&lt;/li&gt;
&lt;li&gt;promptlint picks the model (pre-route hook)&lt;/li&gt;
&lt;li&gt;archlint validates output (quality gate stage)&lt;/li&gt;
&lt;li&gt;costlint tracks cost (telemetry consumer)&lt;/li&gt;
&lt;li&gt;seclint filters incoming prompts (pre-filter)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="get-started"&gt;Get Started
&lt;/h2&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Install all tools&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;go install github.com/mshogin/archlint@latest
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;go install github.com/mikeshogin/promptlint/cmd/promptlint@latest
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;go install github.com/mikeshogin/costlint/cmd/costlint@latest
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;go install github.com/mikeshogin/seclint/cmd/seclint@latest
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Start routing&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;promptlint serve &lt;span class="m"&gt;8090&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;seclint serve &lt;span class="m"&gt;8091&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Check architecture&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;archlint scan --format json ./my-project/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# View costs&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;costlint report --source ~/.promptlint/telemetry.jsonl
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id="links"&gt;Links
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/mshogin/archlint" target="_blank" rel="noopener"
&gt;archlint&lt;/a&gt; - architecture linter&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/mikeshogin/promptlint" target="_blank" rel="noopener"
&gt;promptlint&lt;/a&gt; - complexity router&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/mikeshogin/costlint" target="_blank" rel="noopener"
&gt;costlint&lt;/a&gt; - cost analysis&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/mikeshogin/seclint" target="_blank" rel="noopener"
&gt;seclint&lt;/a&gt; / &lt;a class="link" href="https://github.com/mikeshogin/promptsec" target="_blank" rel="noopener"
&gt;promptsec&lt;/a&gt; - content filter&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/kgatilin/myhome" target="_blank" rel="noopener"
&gt;myhome&lt;/a&gt; - agent orchestration&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/mshogin/archlint/blob/main/ECOSYSTEM.md" target="_blank" rel="noopener"
&gt;ECOSYSTEM.md&lt;/a&gt; - integration map&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Three blockers that prevent technical leaders from growing</title><link>https://mshogin.com/blog/leadership-blockers/</link><pubDate>Mon, 16 Mar 2026 00:00:00 +0000</pubDate><guid>https://mshogin.com/blog/leadership-blockers/</guid><description>&lt;img src="https://mshogin.com/blog/leadership-blockers/cover.en.svg" alt="Featured image of post Three blockers that prevent technical leaders from growing" /&gt;&lt;p&gt;AI is changing IT faster than we can adapt. Roles are transforming. Skills that paid well yesterday are losing value today.&lt;/p&gt;
&lt;p&gt;To maintain your standard of living, you need to grow. But growth doesn&amp;rsquo;t stall because of technology. Not because of your stack. Not because of certifications.&lt;/p&gt;
&lt;p&gt;It stalls because of how you think.&lt;/p&gt;
&lt;p&gt;Strong professionals get stuck. Not because they lack knowledge. But because there are internal blockers that are hard to see on your own.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve been working with system architecture for over fifteen years. And in recent years I&amp;rsquo;ve noticed: the most serious bugs aren&amp;rsquo;t in code. They&amp;rsquo;re in the heads of people who write that code and manage those who write it.&lt;/p&gt;
&lt;p&gt;Here are three patterns I see most often. In others. And in myself.&lt;/p&gt;
&lt;h2 id="blocker-1-territory-defense"&gt;Blocker 1: Territory defense
&lt;/h2&gt;&lt;p&gt;Every leader has a zone of responsibility. And any entry into it feels like an attack. It&amp;rsquo;s instinct - like a predator patrolling its boundaries.&lt;/p&gt;
&lt;h3 id="what-it-looks-like"&gt;What it looks like
&lt;/h3&gt;&lt;p&gt;Imagine this. You&amp;rsquo;re an architect. A system analyst on your team starts making architectural decisions independently. Doing a decent job, but without checking with you. You see the result - the decisions work, but you feel an irritation inside that&amp;rsquo;s hard to explain rationally.&lt;/p&gt;
&lt;p&gt;In a meeting, you start pushing back. Not because the decision was bad - but because it was made without you. Officially you&amp;rsquo;re talking about quality and process. In reality, you&amp;rsquo;re defending territory.&lt;/p&gt;
&lt;p&gt;Another example. A team lead notices that a senior on the team is starting to take on architectural questions. Instead of giving space and helping them grow, the lead tightens control. More reviews. More approvals. More questions like &amp;ldquo;did you think about&amp;hellip;&amp;rdquo;. Officially - concern for quality. In reality - fear of becoming unnecessary.&lt;/p&gt;
&lt;h3 id="why-this-is-a-blocker"&gt;Why this is a blocker
&lt;/h3&gt;&lt;p&gt;The problem isn&amp;rsquo;t defense. Protecting boundaries is normal.&lt;/p&gt;
&lt;p&gt;The problem is HOW you defend them. From confidence in your abilities - or from fear that something will be taken away? The first is leadership. The second is aggression that people feel. And they leave.&lt;/p&gt;
&lt;p&gt;If we draw an analogy with systems: it&amp;rsquo;s like a microservice that instead of providing an API for interaction, closes all ports and returns 403 to every request. Technically it works. But the system around it degrades.&lt;/p&gt;
&lt;h3 id="the-skill"&gt;The skill
&lt;/h3&gt;&lt;p&gt;Distinguish real threats from phantom ones. One question to yourself: &amp;ldquo;am I protecting quality right now - or protecting my ego?&amp;rdquo;&lt;/p&gt;
&lt;h2 id="blocker-2-craving-recognition"&gt;Blocker 2: Craving recognition
&lt;/h2&gt;&lt;p&gt;This is really about feedback.&lt;/p&gt;
&lt;h3 id="what-it-looks-like-1"&gt;What it looks like
&lt;/h3&gt;&lt;p&gt;You did excellent work. Designed a system that handles the load. Ran a review process that raised code quality across the team. Solved a problem that nobody could crack for six months.&lt;/p&gt;
&lt;p&gt;And silence. Nobody came over and said &amp;ldquo;great work.&amp;rdquo; Your manager is quiet. The team took the result for granted.&lt;/p&gt;
&lt;p&gt;In that silence, your brain starts filling in the gaps: &amp;ldquo;I must be doing a bad job.&amp;rdquo; Or worse: &amp;ldquo;they don&amp;rsquo;t value what I do.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;A familiar story: an architect built an API review process for system analysts. Specification quality went up. Integration-phase bugs went down. But the manager never once said &amp;ldquo;good work.&amp;rdquo; At some point the architect started wondering - was it even worth spending time on this.&lt;/p&gt;
&lt;p&gt;Another example. A senior developer spent a month refactoring a critical module. Code got cleaner, tests more reliable, deploy time cut in half. At the retro, nobody even mentioned it. The senior started losing motivation - not because the work was meaningless, but because nobody noticed.&lt;/p&gt;
&lt;h3 id="why-this-is-a-blocker-1"&gt;Why this is a blocker
&lt;/h3&gt;&lt;p&gt;In adult life, nobody will come and say &amp;ldquo;well done.&amp;rdquo; Parents did that. At work - silence. And in that silence, your brain starts making things up.&lt;/p&gt;
&lt;p&gt;Looking at it as a system: you have no observability for your own value. No metrics, no dashboard, no alerts. You&amp;rsquo;re working blind and relying on a single indicator - external praise. And that indicator is unreliable. It depends on your manager&amp;rsquo;s mood, on company culture, on a thousand factors you don&amp;rsquo;t control.&lt;/p&gt;
&lt;h3 id="the-skill-1"&gt;The skill
&lt;/h3&gt;&lt;p&gt;Either learn to ask for feedback - that&amp;rsquo;s not weakness, it&amp;rsquo;s maturity. Or build an internal foundation that doesn&amp;rsquo;t depend on other people&amp;rsquo;s words.&lt;/p&gt;
&lt;p&gt;Practically: keep your own achievement log. Once a week, write down what you did and what effect it had. In six months you&amp;rsquo;ll have an objective picture - regardless of whether your manager noticed.&lt;/p&gt;
&lt;h2 id="blocker-3-the-experience-trap"&gt;Blocker 3: The experience trap
&lt;/h2&gt;&lt;p&gt;Deep experience creates an illusion: &amp;ldquo;I know more, therefore I&amp;rsquo;m owed something.&amp;rdquo;&lt;/p&gt;
&lt;h3 id="what-it-looks-like-2"&gt;What it looks like
&lt;/h3&gt;&lt;p&gt;A meeting. You&amp;rsquo;re the most experienced person in the room. A junior proposes a solution. You see problems in it. And instead of asking a question - &amp;ldquo;what happens at 10x load?&amp;rdquo; - you say: &amp;ldquo;no, that&amp;rsquo;s not how it&amp;rsquo;s done, I&amp;rsquo;ve been doing this for ten years and I know.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Technically you&amp;rsquo;re right. The solution might not handle the load. But you killed two things: the junior&amp;rsquo;s initiative and the team&amp;rsquo;s ability to learn to think independently.&lt;/p&gt;
&lt;p&gt;Another example. An experienced team lead joins a new team. They have three successful projects behind them using a specific stack. The team uses a different approach. Instead of understanding why that approach was chosen, the lead starts pushing their own. Not because it&amp;rsquo;s better - but because it&amp;rsquo;s familiar. And because accepting someone else&amp;rsquo;s approach means accepting that your experience isn&amp;rsquo;t universal.&lt;/p&gt;
&lt;p&gt;I catch myself doing this. Sometimes I push with experience instead of listening. And every time I catch myself, I ask: am I teaching right now - or proving?&lt;/p&gt;
&lt;h3 id="why-this-is-a-blocker-2"&gt;Why this is a blocker
&lt;/h3&gt;&lt;p&gt;The world is transforming. Old patterns are breaking down. In the age of AI, yesterday&amp;rsquo;s expert is learning from scratch today. Experience is valuable, but it&amp;rsquo;s not currency to exchange for submission.&lt;/p&gt;
&lt;p&gt;As a system analogy: it&amp;rsquo;s a legacy service with hardcoded configuration. It used to work perfectly. But the world around it changed, and it still expects requests in the old format. And instead of adapting its API, it demands that everything else adapts to it.&lt;/p&gt;
&lt;h3 id="the-skill-2"&gt;The skill
&lt;/h3&gt;&lt;p&gt;Treat colleagues as equals. Regardless of the experience gap. This doesn&amp;rsquo;t mean ignoring your experience - it means sharing it through questions, not through pressure.&lt;/p&gt;
&lt;h2 id="three-blockers-three-skills-none-about-technology"&gt;Three blockers. Three skills. None about technology
&lt;/h2&gt;&lt;p&gt;Territory defense, craving recognition, the experience trap. These patterns can&amp;rsquo;t be solved by reading books or taking courses. They&amp;rsquo;re embedded in your thinking architecture so deeply that they&amp;rsquo;re hard to see on your own.&lt;/p&gt;
&lt;p&gt;Like in any project: to see architectural problems, you need an outside perspective. The one inside the system sees individual symptoms. The one outside sees the pattern.&lt;/p&gt;
&lt;p&gt;Leadership starts not with the architecture of systems, but with the architecture of thinking. And if you feel stuck - maybe it&amp;rsquo;s not that you don&amp;rsquo;t know enough. Maybe it&amp;rsquo;s time to look at your thinking as a system and run an honest audit on it.&lt;/p&gt;</description></item><item><title>Фаулер про LLM и разработчиков: cognitive debt, supervisory programming и кто на самом деле под ударом</title><link>https://mshogin.com/blog/fowler-llm-developers/</link><pubDate>Fri, 13 Feb 2026 00:00:00 +0000</pubDate><guid>https://mshogin.com/blog/fowler-llm-developers/</guid><description>&lt;img src="https://mshogin.com/cover.svg" alt="Featured image of post Фаулер про LLM и разработчиков: cognitive debt, supervisory programming и кто на самом деле под ударом" /&gt;&lt;p&gt;Мартин Фаулер опубликовал заметки с встречи senior-разработчиков, посвященной LLM. Не очередной хайп про &amp;ldquo;AI заменит всех&amp;rdquo; - а трезвый разбор от людей, которые пишут код десятилетиями.&lt;/p&gt;
&lt;p&gt;Несколько тезисов зацепили настолько, что захотелось разобрать их подробнее. С примерами из собственной практики.&lt;/p&gt;
&lt;h2 id="mid-level-под-ударом-а-не-джуны"&gt;Mid-level под ударом, а не джуны
&lt;/h2&gt;&lt;p&gt;Обычно все переживают за junior-разработчиков: их-то заменят первыми. Фаулер с группой пришли к обратному выводу.&lt;/p&gt;
&lt;p&gt;Джуны адаптивны. Они росли с LLM, умеют ими пользоваться, открыты к новому. Сеньоры понимают архитектуру, видят систему целиком, эффективно управляют агентами - примерно как управляют джунами.&lt;/p&gt;
&lt;p&gt;А mid-level? Они сформировались без LLM, но еще не набрали достаточно опыта, чтобы эффективно ими управлять. Застряли между двумя мирами.&lt;/p&gt;
&lt;p&gt;На практике я вижу это так: mid-level разработчик умеет писать код. Хорошо умеет. Но когда LLM генерирует код быстрее - &amp;ldquo;умение писать код&amp;rdquo; перестает быть конкурентным преимуществом. А понимание &amp;ldquo;зачем этот код нужен&amp;rdquo;, &amp;ldquo;как он вписывается в систему&amp;rdquo;, &amp;ldquo;какие trade-offs мы принимаем&amp;rdquo; - это уже территория сеньоров.&lt;/p&gt;
&lt;p&gt;Один из участников рассказал показательную историю: сеньоры в их компании были резко против LLM. Но когда их заставили поработать руками - треть моментально стала pro-LLM. Практический опыт важнее теоретических страхов. Как пошутили на встрече, некоторые негативные мнения о LLM &amp;ldquo;остались в январе&amp;rdquo;.&lt;/p&gt;
&lt;h3 id="что-делать-mid-level"&gt;Что делать mid-level
&lt;/h3&gt;&lt;p&gt;Если ты mid-level - у тебя есть окно. Не в том, чтобы учиться промптить. А в том, чтобы быстрее набирать архитектурное мышление: понимание систем, trade-offs, бизнес-контекста. То, что LLM пока делает плохо.&lt;/p&gt;
&lt;h2 id="cognitive-debt-опаснее-technical-debt"&gt;Cognitive debt опаснее technical debt
&lt;/h2&gt;&lt;p&gt;Это, на мой взгляд, самый ценный тезис. Фаулер ссылается на исследование Margaret-Anne Storey и проводит параллель с technical debt.&lt;/p&gt;
&lt;p&gt;Её кейс: студенческие команды строили продукт, генерируя код с помощью LLM. К 7-8 неделе одна команда уперлась в стену - любое изменение ломало что-то неожиданное. Сначала обвинили технический долг. Но реальная проблема была в другом: никто в команде не мог объяснить, почему были приняты те или иные решения. Shared understanding - общее понимание системы - фрагментировалось и исчезло.&lt;/p&gt;
&lt;p&gt;Фаулер разделяет это на два слоя:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Cruft&lt;/strong&gt; (хлам в коде) -&amp;gt; в когнитивной сфере это &lt;strong&gt;ignorance&lt;/strong&gt; (невежество) - незнание кода и домена&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Debt&lt;/strong&gt; (долг как метафора стоимости) -&amp;gt; либо платишь &amp;ldquo;проценты&amp;rdquo; (каждое изменение дороже), либо &amp;ldquo;гасишь тело&amp;rdquo; (инвестируешь в понимание)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Это точное попадание в то, что я вижу при приемке проектов. Не раз сталкивался с ситуацией: код написан грамотно, тесты есть, линтеры проходят - но никто не может объяснить, почему выбрана такая декомпозиция сервисов. Или зачем нужен этот промежуточный слой. Документация говорит &amp;ldquo;что&amp;rdquo;, но не говорит &amp;ldquo;зачем&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;С LLM-агентами cognitive debt будет масштабироваться: код генерируется быстрее, чем команда успевает его осмыслить. Скорость создания кода перестает быть ограничителем. Ограничителем становится скорость понимания.&lt;/p&gt;
&lt;h3 id="как-с-этим-работать"&gt;Как с этим работать
&lt;/h3&gt;&lt;p&gt;Несколько практик, которые помогают:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;ADR (Architecture Decision Records)&lt;/strong&gt; - фиксируем не &amp;ldquo;что решили&amp;rdquo;, а &amp;ldquo;почему решили и какие варианты отвергли&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Коучинговые вопросы на ревью&lt;/strong&gt; - вместо &amp;ldquo;используй Strategy pattern&amp;rdquo; спрашивать &amp;ldquo;какие варианты ты рассмотрел? какие trade-offs?&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Обязательный контекст в PR&lt;/strong&gt; - не просто diff, а &amp;ldquo;зачем&amp;rdquo; это изменение нужно&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Если LLM генерирует код - пусть генерирует и ADR к нему. Хотя бы черновик для ревью.&lt;/p&gt;
&lt;h2 id="devex-и-agent-experience---это-круг"&gt;DevEx и Agent Experience - это круг
&lt;/h2&gt;&lt;p&gt;Laura Tacho сказала фразу, которая заслуживает стать мемом:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The Venn Diagram of Developer Experience and Agent Experience is a circle&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Всё, за что годами боролись в developer experience - гладкий тулинг, понятная документация, чистая модульность, осмысленные имена - оказывается, помогает и LLM-агентам. Хорошая модульность и descriptive naming так же полезны для трансформера, как и для &amp;ldquo;более мягких нейронных сетей&amp;rdquo; (мозгов).&lt;/p&gt;
&lt;p&gt;И горькая ирония: менеджмент готов инвестировать в &amp;ldquo;smooth path для LLM&amp;rdquo;, но не готов был делать это для людей. Экзекьютивам не жалко денег на роботов, но жалко на разработчиков.&lt;/p&gt;
&lt;p&gt;Из моего опыта: чистая архитектура с явными зависимостями, маленькими интерфейсами и четкими слоями - это ровно то, что позволяет LLM-агенту эффективно работать с кодобазой. Когда я настраивал Claude Code для работы со своими проектами, разница была заметна сразу: в проекте с чистой архитектурой агент находит нужный контекст за секунды. В проекте-монолите с неявными зависимостями - путается, галлюцинирует, предлагает изменения не в тех файлах.&lt;/p&gt;
&lt;p&gt;Вывод неутешительный и простой: если ваша кодобаза - хаос для людей, она будет хаосом и для агентов. Инвестиции в DevEx теперь имеют двойной ROI.&lt;/p&gt;
&lt;h2 id="supervisory-programming-и-менеджерское-выгорание"&gt;Supervisory programming и менеджерское выгорание
&lt;/h2&gt;&lt;p&gt;Камилла Фурнье заметила:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The part of &amp;ldquo;everyone becomes a manager&amp;rdquo; in AI that I didn&amp;rsquo;t really think about until now was the mental fatigue of context switching&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Тренд &amp;ldquo;один программист управляет несколькими агентами&amp;rdquo; несет с собой ровно ту же болезнь, от которой годами страдают менеджеры: усталость от переключения контекста. Держать в голове 5 параллельных задач, ревьюить результаты из разных контекстов, ловить ошибки в коде, который ты не писал - это менеджмент, а не программирование.&lt;/p&gt;
&lt;p&gt;Фаулер осторожно предполагает, что два человека + агенты могут быть эффективнее, чем один человек + много агентов. Парное программирование нового формата: два мозга ловят ошибки &amp;ldquo;джинна&amp;rdquo; лучше, чем один.&lt;/p&gt;
&lt;p&gt;Мне эта мысль близка. В коучинге есть концепция: сам себе коучем быть нельзя, нужен внешний наблюдатель. С кодом похоже - второй человек видит то, что ты пропустил. А когда агенты генерируют код быстрее, чем один человек может ревьюить - второй мозг не роскошь, а необходимость.&lt;/p&gt;
&lt;h3 id="workload-creep"&gt;Workload creep
&lt;/h3&gt;&lt;p&gt;Фаулер также цитирует исследование из Harvard Business Review: в компании на 200 человек после внедрения AI сотрудники стали работать быстрее, брать больше задач, работать больше часов - часто без просьбы. Звучит как мечта менеджера. Но за первоначальным всплеском приходит: cognitive fatigue, выгорание, ухудшение качества решений.&lt;/p&gt;
&lt;p&gt;Это классический паттерн. Новый инструмент дает эйфорию -&amp;gt; берешь больше -&amp;gt; не замечаешь, как нагрузка выросла -&amp;gt; burnout.&lt;/p&gt;
&lt;h2 id="размер-команд"&gt;Размер команд
&lt;/h2&gt;&lt;p&gt;Уменьшатся ли команды? Фаулер склоняется к &amp;ldquo;нет&amp;rdquo;. Two-pizza teams (5-8 человек) останутся примерно того же размера - но будут делать значительно больше. Есть что-то фундаментальное в размере команды, что балансирует выгоды сотрудничества с издержками координации. LLM не едят пиццу, но они и не добавляют в team dynamics.&lt;/p&gt;
&lt;h2 id="будущее-ide"&gt;Будущее IDE
&lt;/h2&gt;&lt;p&gt;Отдельная тема - будущее IDE. LLM не заменяют IDE, а встраиваются в них. Переименовать функцию через LLM - это как забивать гвоздь микроскопом. Но LLM может оркестрировать инструменты IDE: увидеть, что &amp;ldquo;person&amp;rdquo; нужно переименовать в &amp;ldquo;contact&amp;rdquo; во всех контекстах (функции, поля, документация, тесты), и использовать детерминистические рефакторинги IDE для каждого из них.&lt;/p&gt;
&lt;p&gt;Мне как пользователю Emacs это особенно резонирует. IDE - это мощный инструмент, но мало кто использует его на полную. LLM может стать тем слоем, который знает возможности IDE лучше пользователя и подсказывает, когда использовать LLM, когда - детерминистический рефакторинг, а когда - их комбинацию.&lt;/p&gt;
&lt;h2 id="итого"&gt;Итого
&lt;/h2&gt;&lt;p&gt;Главные мысли из текста Фаулера:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Mid-level под ударом&lt;/strong&gt; - не джуны, как все думали. Окно для роста: быстрее набирать архитектурное мышление&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cognitive debt &amp;gt; technical debt&lt;/strong&gt; - с LLM код генерируется быстрее, чем осмысляется. Ограничитель теперь - понимание, а не написание&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;DevEx = Agent Experience&lt;/strong&gt; - инвестиции в чистую архитектуру дают двойной ROI&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Supervisory programming = менеджерское выгорание&lt;/strong&gt; - context switching утомляет. Пара людей + агенты может быть лучше одиночки + много агентов&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Workload creep&lt;/strong&gt; - эйфория от AI -&amp;gt; перегрузка -&amp;gt; burnout. Классика&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Текст Фаулера ценен тем, что он не про хайп и не про страх. Он про трезвую оценку: что меняется, что остается, и какие новые проблемы приходят вместе с новыми возможностями.&lt;/p&gt;
&lt;p&gt;А ты замечаешь cognitive debt в своих проектах?&lt;/p&gt;</description></item><item><title>Архитектура памяти для AI-агентов: как я научил Claude Code помнить</title><link>https://mshogin.com/blog/memory-architecture-for-ai-agents/</link><pubDate>Wed, 11 Feb 2026 00:00:00 +0000</pubDate><guid>https://mshogin.com/blog/memory-architecture-for-ai-agents/</guid><description>&lt;img src="https://mshogin.com/blog/memory-architecture-for-ai-agents/cover.svg" alt="Featured image of post Архитектура памяти для AI-агентов: как я научил Claude Code помнить" /&gt;&lt;h2 id="боль-агент-с-амнезией"&gt;Боль: агент с амнезией
&lt;/h2&gt;&lt;p&gt;Каждый, кто работает с AI-агентами, знает ощущение: ты объяснил контекст проекта, показал структуру, обсудил решения - а в следующей сессии агент всё забыл. Опять здрасьте. Опять &amp;ldquo;расскажите про ваш проект&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Это как работать с архитектором, у которого каждое утро стирается память. Он талантлив, быстр, но каждый день - новый человек.&lt;/p&gt;
&lt;p&gt;У меня 12+ активных контекстов: рабочие проекты (Wildberries), личные проекты (aitrader, archlint), блог, коучинговая практика, обучение, целеполагание. Переключение между ними без памяти превращалось в ритуал: 5-10 минут на &amp;ldquo;загрузку контекста&amp;rdquo; в начале каждой сессии.&lt;/p&gt;
&lt;p&gt;Стало ясно: нужна архитектура памяти.&lt;/p&gt;
&lt;h2 id="как-устроена-человеческая-память"&gt;Как устроена человеческая память
&lt;/h2&gt;&lt;p&gt;Прежде чем проектировать, я посмотрел на то, как работает память у людей. Параллельно с архитектурой я изучаю коучинг - и там постоянно всплывает тема того, как люди обрабатывают информацию. Заметил структурное сходство.&lt;/p&gt;
&lt;div class="mermaid"&gt;
flowchart TD
A["Входящие данные"] --&gt; B["Рабочая память\n(Short-Term)\nАктивные задачи,\nтекущий контекст"]
B --&gt; C{"Фильтр ценности\n(еженедельный ревью)"}
C --&gt;|"Ценно"| D["Долговременная память\n(Long-Term)\nПаттерны, принципы, уроки"]
C --&gt;|"Обработано"| E["Архив\n(забыто, но доступно)"]
&lt;/div&gt;
&lt;p&gt;У людей так же:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Рабочая память&lt;/strong&gt; (Short-Term) - то, с чем работаешь прямо сейчас. Ограничена: ~7 элементов одновременно. Через 3-6 месяцев без обращения - забывается.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Долговременная память&lt;/strong&gt; (Long-Term) - дистиллированные знания. Не &amp;ldquo;что я делал во вторник&amp;rdquo;, а &amp;ldquo;какой паттерн я увидел за три месяца работы&amp;rdquo;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Архив&lt;/strong&gt; - не удалено, но не на поверхности. Доступно при целенаправленном поиске.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ключевой момент: переход из Short-Term в Long-Term - не автоматический. Нужна осознанная обработка. В коучинге это рефлексия. В моей системе - еженедельный ревью.&lt;/p&gt;
&lt;h2 id="архитектура-решения"&gt;Архитектура решения
&lt;/h2&gt;&lt;h3 id="три-уровня-памяти"&gt;Три уровня памяти
&lt;/h3&gt;&lt;p&gt;Я реализовал три уровня, зеркалирующих человеческую модель:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;~/my/org-roam/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+-- Short-Term-Memory/ # Рабочая память (3-6 месяцев)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| +-- Wildberries/ # Рабочий контекст
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| +-- Coaching/ # Коучинговые сессии
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| +-- daily/ # Ежедневные заметки
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| +-- todos.md # Задачи
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;|
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+-- Long-Term-Memory/ # Долговременная память
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| +-- Coaching/ # Методики, паттерны, кейсы
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| +-- Architecture/ # Архитектурные решения
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| +-- Posts/ # Публикации
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| +-- Personal/ # Личные принципы
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;|
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+-- Archive/ # Архив (по месяцам)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; +-- 2026/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; +-- 01-January/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; +-- 02-February/
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Short-Term&lt;/strong&gt; - inbox для всего нового. Сырые заметки, текущие задачи, эксперименты. Максимум 50 активных файлов. Если больше - пора делать ревью.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Long-Term&lt;/strong&gt; - база знаний. Сюда попадает только то, что прошло фильтр ценности:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Переиспользуемость (применимо 3+ раз)&lt;/li&gt;
&lt;li&gt;Обучающая ценность (ага-момент, важная ошибка)&lt;/li&gt;
&lt;li&gt;Референсная ценность (пример для копирования)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Archive&lt;/strong&gt; - завершенные проекты, обработанные заметки. Не удалено, но убрано с глаз.&lt;/p&gt;
&lt;h3 id="контексты-переключение-за-секунду"&gt;Контексты: переключение за секунду
&lt;/h3&gt;&lt;p&gt;Вторая проблема - переключение между проектами. Решение: система контекстов.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;contexts&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;coaching&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;coaching&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;description&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Коучинговые сессии и практика развития&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;directory&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;~/my/coaching&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;memory&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;short_term&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;~/my/org-roam/Short-Term-Memory/Coaching&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;long_term&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;~/my/org-roam/Long-Term-Memory/Coaching&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;archlint&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;archlint&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;description&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;ArchLint - линтер архитектуры Go проектов&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;directory&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;~/my/archlint&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;memory&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;short_term&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;long_term&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Каждый контекст знает:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;directory&lt;/strong&gt; - рабочая директория проекта&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;memory.short_term&lt;/strong&gt; - где хранить текущие заметки&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;memory.long_term&lt;/strong&gt; - где хранить дистиллированные знания&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Переключение: одна команда &lt;code&gt;/w coaching&lt;/code&gt; - и агент знает где он, что помнить, какие файлы читать.&lt;/p&gt;
&lt;h3 id="индекс-активностей-навигация-по-всему"&gt;Индекс активностей: навигация по всему
&lt;/h3&gt;&lt;p&gt;Контексты решают проблему &amp;ldquo;где я&amp;rdquo;. Но остается вопрос: &amp;ldquo;где искать информацию по теме X?&amp;rdquo;. Для этого - глобальный индекс активностей.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-markdown" data-lang="markdown"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;### Коучинг / Практика
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; Keywords: сессия, клиент, практика, рефлексия
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; Файлы:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;-&lt;/span&gt; Практика: ~/my/org-roam/Long-Term-Memory/Coaching/03-Практика/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;-&lt;/span&gt; Гайды сессий: ~/my/org-roam/Long-Term-Memory/Coaching/session-guides/INDEX.md
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;### Здоровье и психология
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; Keywords: психолог, здоровье, границы, стыд
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; Файлы:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;-&lt;/span&gt; Темы: ~/my/org-roam/Long-Term-Memory/Темы для психолога.md
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; Связанные активности: Коучинг / Запросы для проработки
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Принцип работы:&lt;/p&gt;
&lt;div class="mermaid"&gt;
flowchart TD
A["Промпт пользователя"] --&gt; B["Поиск по keywords\nв memory-index.md"]
B --&gt; C{"Найдена\nактивность?"}
C --&gt;|"Да"| D["Работай в её контексте"]
C --&gt;|"Нет"| E["Спроси пользователя,\nпредложи варианты"]
&lt;/div&gt;
&lt;h3 id="кросс-контекстный-поиск-связи-между-контекстами"&gt;Кросс-контекстный поиск: связи между контекстами
&lt;/h3&gt;&lt;p&gt;Самая интересная архитектурная задача. Информация часто пересекает границы контекстов.&lt;/p&gt;
&lt;p&gt;Пример: тема &amp;ldquo;границы&amp;rdquo; может всплыть в коучинге (запрос клиента), в психологии (тема для терапии), в рабочем контексте (обратная связь коллеге). Как не потерять связь?&lt;/p&gt;
&lt;p&gt;Решение: &lt;strong&gt;кросс-ссылки на уровне глобального индекса&lt;/strong&gt;, а не дублирование информации между контекстными индексами.&lt;/p&gt;
&lt;div class="mermaid"&gt;
flowchart TD
G["memory-index.md\n(глобальный индекс)"] --&gt; C1["Coaching\nINDEX.md"]
G --&gt; C2["Здоровье\n(файлы)"]
G --&gt; C3["Работа\nINDEX.md"]
G --&gt; C4["..."]
C1 -.-|"кросс-ссылка"| C2
C2 -.-|"кросс-ссылка"| C3
style G fill:#0f3460,color:#fff
style C1 fill:#533483,color:#fff
style C2 fill:#533483,color:#fff
style C3 fill:#533483,color:#fff
style C4 fill:#333,color:#999
&lt;/div&gt;
&lt;p&gt;Правило: каждый контекстный индекс отвечает только за свой контекст. Связь между контекстами - через поле &amp;ldquo;Связанные активности&amp;rdquo; в глобальном индексе.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-markdown" data-lang="markdown"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Кросс-ссылки между активностями
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| Активность A | Активность B | Связь |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;|--------------------------|------------------------|-------------------------------------|
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| Коучинг / Запросы | Здоровье и психология | Запрос &lt;span class="ni"&gt;#11&lt;/span&gt; = Тема &lt;span class="ni"&gt;#2&lt;/span&gt; (границы) |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| Семья | Коучинг / Запросы | Запрос &lt;span class="ni"&gt;#3&lt;/span&gt; (темы с супругой) |
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Антипаттерн: дублировать ссылки на &amp;ldquo;Темы для психолога&amp;rdquo; внутри Coaching/INDEX.md. Это нарушает single responsibility - индекс коучинга не должен знать про психологию. Связь - только через глобальный уровень.&lt;/p&gt;
&lt;h2 id="жизненный-цикл-знаний"&gt;Жизненный цикл знаний
&lt;/h2&gt;&lt;p&gt;Данные без обработки - мусор. Система памяти работает, только если есть процесс трансформации.&lt;/p&gt;
&lt;div class="mermaid"&gt;
flowchart LR
subgraph ST ["Short-Term (сырые данные)"]
A1["Заметки по сессии\nс клиентом X"]
A2["Тикеты проекта\nархитектуры"]
A3["Исследование\nTarjan алгоритма"]
end
subgraph LT ["Long-Term (знания)"]
B1["Паттерн: Работа с\nпрокрастинацией\nчерез ценности"]
B2["ADR-0042: Выбор\nмежду монолитом\nи микросервисами"]
B3["Библиотека\nалгоритмов\nпоиска циклов"]
end
A1 --&gt;|"трансформация"| B1
A2 --&gt;|"трансформация"| B2
A3 --&gt;|"трансформация"| B3
&lt;/div&gt;
&lt;h3 id="критерии-перехода-в-long-term"&gt;Критерии перехода в Long-Term
&lt;/h3&gt;&lt;p&gt;Не всё заслуживает долговременной памяти. Четыре фильтра:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Переиспользуемость&lt;/strong&gt; - применимо 3+ раз (методики, шаблоны, чек-листы)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Обучающая ценность&lt;/strong&gt; - ага-момент, важная ошибка, смена парадигмы&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Референсная ценность&lt;/strong&gt; - пример для копирования (код, кейс, формат)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Паттерн&lt;/strong&gt; - повторяющаяся проблема + решение&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Всё остальное - одноразовые заметки, устаревшие TODO, рутинные логи - удаляется или уходит в архив.&lt;/p&gt;
&lt;h3 id="еженедельный-ревью"&gt;Еженедельный ревью
&lt;/h3&gt;&lt;p&gt;Раз в неделю - 30-40 минут на обработку Short-Term:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Просмотреть файлы за неделю&lt;/li&gt;
&lt;li&gt;Выделить ценное для Long-Term&lt;/li&gt;
&lt;li&gt;Трансформировать: сырые данные -&amp;gt; структурированные знания&lt;/li&gt;
&lt;li&gt;Архивировать обработанное&lt;/li&gt;
&lt;li&gt;Удалить мусор&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Метрики здоровой системы:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Short-Term: 30-50 активных файлов&lt;/li&gt;
&lt;li&gt;Long-Term: +2-5 новых записей в неделю&lt;/li&gt;
&lt;li&gt;Archive: регулярное пополнение&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="параллель-с-коучингом"&gt;Параллель с коучингом
&lt;/h2&gt;&lt;p&gt;Когда я проектировал эту систему, я заметил параллели с тем, что изучаю в коучинге.&lt;/p&gt;
&lt;h3 id="short-term--рабочая-осознанность"&gt;Short-Term = Рабочая осознанность
&lt;/h3&gt;&lt;p&gt;Когда человек разбирается в сложной ситуации, он сначала выгружает всё, что на поверхности: факты, эмоции, людей, обстоятельства. Это рабочая память - хаотичная, перегруженная, но актуальная. Short-Term Memory в моей системе работает так же: собирает всё, что сейчас активно, без фильтрации.&lt;/p&gt;
&lt;h3 id="long-term--мудрость-через-рефлексию"&gt;Long-Term = Мудрость через рефлексию
&lt;/h3&gt;&lt;p&gt;Long-Term - это не &amp;ldquo;запомнить всё&amp;rdquo;. Это &amp;ldquo;понять, что важно&amp;rdquo;. Лучшие инсайты приходят не в момент обсуждения, а позже - когда человек рефлексирует и видит паттерн. Еженедельный ревью - это та самая рефлексия, только для базы знаний.&lt;/p&gt;
&lt;h3 id="кросс-контекст--системное-мышление"&gt;Кросс-контекст = Системное мышление
&lt;/h3&gt;&lt;p&gt;Проблема редко живет в одном контексте. Одна и та же тема может всплыть и на работе, и в личных проектах, и в обучении. Кросс-ссылки в системе памяти - это способ видеть одну тему с разных сторон, расширить перспективу.&lt;/p&gt;
&lt;h3 id="architect-of-thinking"&gt;Architect of Thinking
&lt;/h3&gt;&lt;p&gt;Изучая коучинг, я разработал авторский фреймворк на стыке архитектуры и работы с мышлением - Architect of Thinking. Формула:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Контекст -&amp;gt; Цель -&amp;gt; Карта -&amp;gt; Узел -&amp;gt; Решение -&amp;gt; Шаг&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Это ровно то, как архитектор работает с системой: сначала изучи (контекст), определи цель, построй карту, найди bottleneck (узел), спроектируй решение, сделай первый шаг. Тот же подход - к человеческим задачам.&lt;/p&gt;
&lt;h2 id="результаты"&gt;Результаты
&lt;/h2&gt;&lt;h3 id="до-системы-памяти"&gt;До системы памяти:
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;5-10 минут на &amp;ldquo;загрузку контекста&amp;rdquo; каждую сессию&lt;/li&gt;
&lt;li&gt;Потеря решений между сессиями&lt;/li&gt;
&lt;li&gt;Дублирование работы&lt;/li&gt;
&lt;li&gt;Невозможность связать темы между контекстами&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="после"&gt;После:
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;Переключение контекста за 1 команду&lt;/li&gt;
&lt;li&gt;Знания накапливаются и структурируются&lt;/li&gt;
&lt;li&gt;Связи между контекстами через кросс-ссылки&lt;/li&gt;
&lt;li&gt;Еженедельный ревью превращает данные в знания&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="что-дальше"&gt;Что дальше
&lt;/h2&gt;&lt;p&gt;Система живая - она развивается вместе с моими проектами. Следующие шаги:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Автоматизация ревью (AI-помощник для еженедельной обработки Short-Term)&lt;/li&gt;
&lt;li&gt;Семантический поиск по Long-Term Memory&lt;/li&gt;
&lt;li&gt;Версионирование знаний (как знания меняются со временем)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Но главный урок не технический. Проектируя память для AI-агента, я лучше понял, как работает моя собственная. И это, пожалуй, самый ценный побочный эффект.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Исходный код и конфигурации описаны для Claude Code (Anthropic CLI). Подход применим к любому AI-агенту с файловой системой.&lt;/em&gt;&lt;/p&gt;</description></item><item><title>Spec-Driven Development: Controlling AI Code Generation</title><link>https://mshogin.com/blog/spec-driven-development/</link><pubDate>Tue, 09 Dec 2025 00:00:00 +0000</pubDate><guid>https://mshogin.com/blog/spec-driven-development/</guid><description>&lt;img src="https://mshogin.com/blog/spec-driven-development/cover.en.svg" alt="Featured image of post Spec-Driven Development: Controlling AI Code Generation" /&gt;&lt;h2 id="in-this-article"&gt;In this article
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="#observations" &gt;Observations&lt;/a&gt;: the problem with large MRs and AI code generation&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="#hypothesis" &gt;Hypothesis&lt;/a&gt;: specifications as a contract&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="#method" &gt;Method&lt;/a&gt;: storage structure and specification sizes&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="#the-role-of-ai" &gt;The Role of AI&lt;/a&gt;: editor and executor&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="#results" &gt;Results&lt;/a&gt;: reproducibility experiment&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="#limitations" &gt;Limitations&lt;/a&gt; and &lt;a class="link" href="#conclusions" &gt;Conclusions&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="observations"&gt;Observations
&lt;/h2&gt;&lt;p&gt;4000 lines in a single MR. Three hours reviewing, 12 comments, fixes - another 800 lines. On the fourth attempt I closed the tab and realized: the problem isn&amp;rsquo;t the code, it&amp;rsquo;s that nobody knew what exactly needed to be written.&lt;/p&gt;
&lt;p&gt;If you work with large codebases, this situation is familiar. Large MRs are a symptom. When it&amp;rsquo;s unclear what exactly needs to be done, developers write more code than necessary. They add things just in case. Cover scenarios nobody asked for. The MR grows not because the task is big, but because the boundaries are fuzzy.&lt;/p&gt;
&lt;p&gt;Another cause is the illusion that it&amp;rsquo;s easier to do everything in one task than to decompose. It seems like splitting creates extra work. In practice, a monolithic 4000-line MR can&amp;rsquo;t be properly reviewed, and bugs slip through to production.&lt;/p&gt;
&lt;p&gt;I use AI daily. Claude Code is my main tool - it can be configured to use different models: Anthropic, DeepSeek, GPT family, local ones via Ollama. At some point I noticed a pattern: the more precisely I formulate the task, the better the result. Prompts became increasingly structured - simple instructions, then templates, then something resembling technical specifications.&lt;/p&gt;
&lt;p&gt;Where&amp;rsquo;s the problem? At first I thought I was too lazy to give AI detailed instructions. Then I decided the AI Agent wasn&amp;rsquo;t gathering enough context - needed RAG or something similar. Eventually I realized the problem is in both places: creating full instructions feels like overkill, and how to help the agent gather the right context - unclear.&lt;/p&gt;
&lt;p&gt;But the main thing - there&amp;rsquo;s nothing to verify. No artifact you can point to and say: this is what was specified, this is what was built.&lt;/p&gt;
&lt;h2 id="hypothesis"&gt;Hypothesis
&lt;/h2&gt;&lt;p&gt;The idea isn&amp;rsquo;t new - the industry has been talking about spec-first approach for a while. I wanted to try it for a long time and finally decided to test it.&lt;/p&gt;
&lt;p&gt;If requirements are formalized as a specification before coding begins, then:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;AI Agent will generate more predictable code&lt;/li&gt;
&lt;li&gt;Results can be validated against the specification&lt;/li&gt;
&lt;li&gt;Architecture will remain controllable&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;When AI Agent generates hundreds of lines of code per minute, the only way to control the result is to have a formal description of what should be produced, and a tool that verifies the implementation matches the specification. More on the latter in a separate article.&lt;/p&gt;
&lt;h2 id="method"&gt;Method
&lt;/h2&gt;&lt;p&gt;I decided to test the hypothesis on a real project - a tool for building architectural graphs from Go code. The rule was simple: not a single line of code without a specification.&lt;/p&gt;
&lt;p&gt;First specification - &lt;a class="link" href="https://github.com/mshogin/archlint/blob/main/specs/done/0001-init-project.md" target="_blank" rel="noopener"
&gt;create an empty project&lt;/a&gt; with standard Go layout. Second - &lt;a class="link" href="https://github.com/mshogin/archlint/blob/main/specs/done/0003-data-model.md" target="_blank" rel="noopener"
&gt;graph model&lt;/a&gt;. Third - &lt;a class="link" href="https://github.com/mshogin/archlint/blob/main/specs/done/0004-go-analyzer.md" target="_blank" rel="noopener"
&gt;Go code analyzer&lt;/a&gt;. Over several days, 10 completed specifications accumulated.&lt;/p&gt;
&lt;h3 id="storage-structure"&gt;Storage Structure
&lt;/h3&gt;&lt;p&gt;Kanban-like organization via file system:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;specs/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├── todo/ # task queue
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ ├── 0010-feature-x.md
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ └── 0020-feature-y.md
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├── inprogress/ # in progress (maximum one - WIP limit)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ └── 0005-current.md
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;└── done/ # completed
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ├── 0001-init-project.md
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ├── 0003-data-model.md
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; └── 0004-go-analyzer.md
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Prioritization via numeric prefix: lower number - higher priority. State transitions - moving files between directories.&lt;/p&gt;
&lt;div class="mermaid"&gt;
graph LR
TODO["todo/"] --&gt; INPROGRESS["inprogress/"]
INPROGRESS --&gt; DONE["done/"]
&lt;/div&gt;
&lt;h3 id="specification-sizes"&gt;Specification Sizes
&lt;/h3&gt;&lt;p&gt;Classification by time to write the specification (T-shirt sizing):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;S (Small)&lt;/strong&gt; - up to 10 minutes&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;M (Medium)&lt;/strong&gt; - 10-20 minutes&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;L (Large)&lt;/strong&gt; - more than 20 minutes&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Size determines depth of elaboration. S-task: Problem Statement and 5 Acceptance Criteria. L-task: full UML/C4 diagrams, detailed Requirements, 15+ acceptance criteria. Correlation between specification size and result predictability is direct.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re starting from scratch - try an S-specification first. Minimal investment for the experiment.&lt;/p&gt;
&lt;h3 id="s-specification-example-project-initialization"&gt;S-Specification Example: Project Initialization
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;span class="lnt"&gt;25
&lt;/span&gt;&lt;span class="lnt"&gt;26
&lt;/span&gt;&lt;span class="lnt"&gt;27
&lt;/span&gt;&lt;span class="lnt"&gt;28
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-markdown" data-lang="markdown"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gh"&gt;# Spec 0001: Initialize Standard Golang Project Layout
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gh"&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gs"&gt;**Metadata:**&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; Priority: 0001
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; Status: Done
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; Effort: S
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Overview
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;### Problem Statement
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;Need to create basic Go project structure for the archlint tool
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;according to standard development practices.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;### Solution Summary
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;Initialize Go module and create minimal project structure.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Requirements
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;### R1: Go Module Initialization
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;-&lt;/span&gt; Initialize Go module with name github.com/mshogin/archlint
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;### R2: Minimal Directory Structure
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;-&lt;/span&gt; Create cmd/archlint/ for entry point
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; Create internal/ for private code
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; Create pkg/ for public libraries
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Acceptance Criteria
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;- [x]&lt;/span&gt; AC1: go.mod created with module path github.com/mshogin/archlint
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;- [x]&lt;/span&gt; AC2: cmd/archlint/main.go exists and compiles
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;- [x]&lt;/span&gt; AC3: Directories internal/ and pkg/ exist
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Minimum details, maximum specificity. AI gets clear task boundaries.&lt;/p&gt;
&lt;h3 id="m-specification-example-collect-command"&gt;M-Specification Example: Collect Command
&lt;/h3&gt;&lt;p&gt;Medium tasks require diagrams. I experimented with Sequence diagrams - sending them to the agent along with requirements. Noticed that with them the AI Agent produces roughly what&amp;rsquo;s expected.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-markdown" data-lang="markdown"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gh"&gt;# Spec 0006: Implement Collect Command
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gh"&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gs"&gt;**Metadata:**&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; Priority: 0006
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; Status: Done
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; Effort: M
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Overview
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;### Problem Statement
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;Need to implement the collect command for gathering architecture
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;from source code and saving the graph to a YAML file.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;### Solution Summary
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;Create a collect subcommand that uses GoAnalyzer to analyze code
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;and saves the result in YAML format.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Architecture
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;### Sequence Flow (PlantUML)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;title Sequence: Collect Command
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;actor User
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;participant &amp;#34;collectCmd&amp;#34; as CC
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;participant &amp;#34;GoAnalyzer&amp;#34; as GA
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;participant &amp;#34;saveGraph&amp;#34; as SG
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;User -&amp;gt; CC: archlint collect . -o arch.yaml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;CC -&amp;gt; GA: Analyze(dir)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;GA --&amp;gt; CC: *Graph
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;CC -&amp;gt; SG: saveGraph(graph)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;SG --&amp;gt; CC: nil
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;CC --&amp;gt; User: &amp;#34;Graph saved to arch.yaml&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-markdown" data-lang="markdown"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Requirements
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;### R1: Command Definition
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;var collectCmd = &amp;amp;cobra.Command{
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Use: &amp;#34;collect [directory]&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Short: &amp;#34;Collect architecture from source code&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Args: cobra.ExactArgs(1),
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; RunE: runCollect,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;### R2: Flags
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;-o, --output: output YAML file (default: architecture.yaml)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;-l, --language: programming language (default: go)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Acceptance Criteria
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;- [x]&lt;/span&gt; AC1: Command accepts directory as argument
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;- [x]&lt;/span&gt; AC2: Flags -o and -l work
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;- [x]&lt;/span&gt; AC3: Result saved to YAML
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;- [x]&lt;/span&gt; AC4: Statistics printed for components
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Sequence diagram defines call order. AI follows it literally.&lt;/p&gt;
&lt;h3 id="l-specification-example-go-code-analyzer"&gt;L-Specification Example: Go Code Analyzer
&lt;/h3&gt;&lt;p&gt;Large tasks require multiple diagrams - Data Model and Sequence:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-markdown" data-lang="markdown"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gh"&gt;# Spec 0004: Implement Go Code Analyzer
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gh"&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gs"&gt;**Metadata:**&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; Priority: 0004
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; Status: Done
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; Effort: L
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Overview
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;### Problem Statement
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;Need to implement a Go code analyzer that parses source code
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;using AST and builds a dependency graph between components.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;### Solution Summary
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;Create GoAnalyzer in internal/analyzer package that uses
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;go/ast and go/parser to analyze Go files and build the graph.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Architecture
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;### Data Model
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;span class="lnt"&gt;25
&lt;/span&gt;&lt;span class="lnt"&gt;26
&lt;/span&gt;&lt;span class="lnt"&gt;27
&lt;/span&gt;&lt;span class="lnt"&gt;28
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;class GoAnalyzer {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -packages: map[string]*PackageInfo
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -types: map[string]*TypeInfo
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -functions: map[string]*FunctionInfo
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -nodes: []model.Node
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -edges: []model.Edge
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; +NewGoAnalyzer() *GoAnalyzer
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; +Analyze(dir string) (*model.Graph, error)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -parseFile(filename string) error
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -buildGraph()
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;class PackageInfo {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; +Name: string
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; +Path: string
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; +Imports: []string
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;class TypeInfo {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; +Name: string
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; +Package: string
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; +Kind: string
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; +Fields: []FieldInfo
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;GoAnalyzer &amp;#34;1&amp;#34; *-- &amp;#34;*&amp;#34; PackageInfo
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;GoAnalyzer &amp;#34;1&amp;#34; *-- &amp;#34;*&amp;#34; TypeInfo
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-markdown" data-lang="markdown"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;### Sequence Diagram
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;title Sequence: Code Analysis
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;actor User
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;participant &amp;#34;GoAnalyzer&amp;#34; as GA
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;participant &amp;#34;go/parser&amp;#34; as GP
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;participant &amp;#34;buildGraph&amp;#34; as BG
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;User -&amp;gt; GA: Analyze(dir)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;loop For each .go file
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; GA -&amp;gt; GP: ParseFile(filename)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; GP --&amp;gt; GA: *ast.File
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; GA -&amp;gt; GA: Extract packages, types, functions
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;end
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;GA -&amp;gt; BG: buildGraph()
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;BG --&amp;gt; GA: *Graph
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;GA --&amp;gt; User: *Graph, nil
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-markdown" data-lang="markdown"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Requirements
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;### R1: AST Parsing
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;-&lt;/span&gt; Parse all .go files in directory
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; Extract packages, types, functions, methods
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;### R2: Graph Building
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;-&lt;/span&gt; Create Node for each component
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; Create Edge for each relationship (import, calls, uses)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;### R3: External Dependencies
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;-&lt;/span&gt; Identify external dependencies
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; Mark them as entity: external
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Acceptance Criteria
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;&lt;/span&gt;&lt;span class="k"&gt;- [x]&lt;/span&gt; AC1: Analyzer correctly parses Go code
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;- [x]&lt;/span&gt; AC2: All component types extracted
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;- [x]&lt;/span&gt; AC3: All relationship types identified
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;- [x]&lt;/span&gt; AC4: External dependencies identified
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;- [x]&lt;/span&gt; AC5: Graph serializes to YAML
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;For L-tasks multiple diagrams are a necessity. Data Model, Sequence, Component - together they define application architecture and manage dependencies between components.&lt;/p&gt;
&lt;h2 id="the-role-of-ai"&gt;The Role of AI
&lt;/h2&gt;&lt;p&gt;AI accelerates the work, but I don&amp;rsquo;t delegate architecture: decisions are fixed in the specification, go through review, and are verified by validators. However, decisions rarely come from thin air: I bring initial options and constraints, the agent suggests alternatives and highlights blind spots. This affects my thinking, and I&amp;rsquo;m aware of it. The final yes/no and responsibility are mine.&lt;/p&gt;
&lt;p&gt;The agent has two areas of responsibility.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Specification Editor&lt;/strong&gt;
I dictate a raw stream of thoughts by voice (I dictate faster than I type). The agent formats it according to &lt;a class="link" href="https://github.com/mshogin/archlint/blob/main/templates/spec-template.md" target="_blank" rel="noopener"
&gt;my specification template&lt;/a&gt;: organizes into sections, clarifies the unsaid, formulates requirements and acceptance criteria so they can be verified. After that I review and fix the specification as the source contract.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Implementation Executor&lt;/strong&gt;
When the specification is agreed upon, I hand it to the agent for implementation. The agent writes code according to the specification, and I verify the result: review, validation, iterations until the architecture becomes clean and predictable.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="mermaid"&gt;
graph LR
A["Ideas/options (me)"] --&gt; B["AI supplements and formalizes"]
B --&gt; C["Specification"]
C --&gt; D["Review and decisions (me)"]
D --&gt; E["Implementation (AI)"]
&lt;/div&gt;
&lt;h2 id="results"&gt;Results
&lt;/h2&gt;&lt;p&gt;Over several days - 10 completed specifications and a working project. Code matches the architecture from diagrams.&lt;/p&gt;
&lt;p&gt;To test whether specifications are self-sufficient, I ran an experiment: gave Claude Code an empty directory and 10 specifications from archlint - no access to source code. The task: recreate the project from scratch.&lt;/p&gt;
&lt;p&gt;Result in 20 minutes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;85.5%&lt;/strong&gt; reproduction success rate&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;100%&lt;/strong&gt; structural identity (directories, files, types)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;23 mutations&lt;/strong&gt; in implementation details&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Project structure reproduced completely. All acceptance criteria from specifications met. Project compiles and passes tests.&lt;/p&gt;
&lt;p&gt;Mutations occurred where specifications described what to do, but not how. Critical example: the sequence diagram building algorithm was implemented differently - functionally equivalent, but with different call stack traversal logic. Another category of mutations - stylistic: comment language, function order in files, variable naming.&lt;/p&gt;
&lt;p&gt;Takeaway for improving specifications: critical algorithms need pseudocode or concrete input/output examples. A specification with what + how yields more precise reproduction than what alone.&lt;/p&gt;
&lt;p&gt;Full report with mutation catalog: &lt;a class="link" href="https://github.com/mshogin/archlint-reproduction" target="_blank" rel="noopener"
&gt;github.com/mshogin/archlint-reproduction&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="specification-idempotency"&gt;Specification Idempotency
&lt;/h2&gt;&lt;p&gt;For specifications to remain reproducible, all changes must go through them. No tweaks in copilot mode, no chats with &amp;ldquo;fix this thing&amp;rdquo;. Every change - update the specification, then implement.&lt;/p&gt;
&lt;p&gt;This is the main challenge. You want to quickly fix a bug in dialogue rather than go back to the spec. But every such fix - loss of reproducibility.&lt;/p&gt;
&lt;p&gt;The trade-off is obvious:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Need results here and now - copilot mode is faster&lt;/li&gt;
&lt;li&gt;Need reproducibility - only through specifications&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The choice depends on context. Prototype or experiment - copilot. Production code with a long lifecycle - specifications.&lt;/p&gt;
&lt;h2 id="limitations"&gt;Limitations
&lt;/h2&gt;&lt;p&gt;The approach doesn&amp;rsquo;t solve problems automatically. It doesn&amp;rsquo;t replace domain understanding, doesn&amp;rsquo;t invent requirements, and doesn&amp;rsquo;t guarantee good design. It makes errors visible earlier and forces architecture to stay within bounds.&lt;/p&gt;
&lt;p&gt;The cost: time for writing specifications, reviewing them, and iterations after validation. If you treat specs formally, everything slides back into chaos. Honestly ask yourself: are you willing to spend 10-30 minutes on a specification so the agent can implement it in 5-20 minutes?&lt;/p&gt;
&lt;p&gt;Implementation details vary. The reproducibility experiment showed 23 mutations - algorithms are interpreted differently, code style differs. Critical sections need pseudocode, not just descriptions.&lt;/p&gt;
&lt;p&gt;I think the approach works well where there&amp;rsquo;s an established, formed, and working process. Processes focused on discipline, clear areas of responsibility, review, definition of done. You can think of this process as a conveyor delivering software 24/7.&lt;/p&gt;
&lt;h2 id="conclusions"&gt;Conclusions
&lt;/h2&gt;&lt;p&gt;The hypothesis was confirmed:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;AI generates more predictable code - yes, with diagrams present&lt;/li&gt;
&lt;li&gt;Results can be validated - yes, 85.5% reproducibility&lt;/li&gt;
&lt;li&gt;Architecture remains controllable - yes, 100% structural identity&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The essence is simple: without specification there&amp;rsquo;s nothing to verify, with specification - there&amp;rsquo;s an artifact for validation. No need for perfect AI or perfect prompt.&lt;/p&gt;
&lt;p&gt;The experiment continues.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;Templates and examples:&lt;/strong&gt; &lt;a class="link" href="https://github.com/mshogin/archlint" target="_blank" rel="noopener"
&gt;github.com/mshogin/archlint&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re trying the spec-driven approach or already using it - share in the comments what works and what doesn&amp;rsquo;t. I write about AI code generation and architecture practices on Telegram: &lt;a class="link" href="https://t.me/MikeShogin" target="_blank" rel="noopener"
&gt;@MikeShogin&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Structural and Behavioral Architecture: Graph-Based Approach to Complexity Control</title><link>https://mshogin.com/blog/architecture-graphs/</link><pubDate>Tue, 02 Dec 2025 00:00:00 +0000</pubDate><guid>https://mshogin.com/blog/architecture-graphs/</guid><description>&lt;img src="https://mshogin.com/blog/architecture-graphs/cover.en.svg" alt="Featured image of post Structural and Behavioral Architecture: Graph-Based Approach to Complexity Control" /&gt;&lt;h2 id="why-vibe-coding-doesnt-work"&gt;Why Vibe Coding Doesn&amp;rsquo;t Work
&lt;/h2&gt;&lt;p&gt;With the emergence of AI agents, software development has changed dramatically. Like many developers, I started actively using Claude, Cursor, and other tools to automate code writing. The results were initially impressive: in one evening, doing system analysis, architecture design, and prompt engineering, I could generate up to 100,000 lines of code.&lt;/p&gt;
&lt;p&gt;The process was engaging. There was no need to manually write implementations - just describe requirements, discuss architectural vision with AI, clarify details, and code would appear. I could work on my pet projects in the evenings, talking with artificial intelligence like a colleague. This was true vibe coding - a pleasant, creative process unburdened by routine.&lt;/p&gt;
&lt;p&gt;Problems didn&amp;rsquo;t start immediately. The first few days went smoothly: AI quickly generated code, tests passed, functionality worked. But then, after about a week or two of active development, I began noticing alarming symptoms.&lt;/p&gt;
&lt;h3 id="symptoms-of-codebase-degradation"&gt;Symptoms of Codebase Degradation
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Agents started slowing down.&lt;/strong&gt; What used to take minutes now required tens of minutes. AI began looping on simple tasks, generating excessive code, suggesting refactoring almost the entire project to fix a small bug. The context grew too large, and the agent got lost in its own code.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Architectural anti-patterns appeared.&lt;/strong&gt; The last straw was when reviewing code I discovered this construction:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// in the main function&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nx"&gt;intermediate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// inside calls processData(input)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nx"&gt;final&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;combine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;intermediate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// inside calls processData(input) again!&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="c1"&gt;// func transform(input) {&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="c1"&gt;// tmp := processData(input)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="c1"&gt;// result := combine(input)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="c1"&gt;// return reuslt * 2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="c1"&gt;// }&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="c1"&gt;//
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// func combine(intermediate) {&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="c1"&gt;// result := processData(input) // same function, same arguments!&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="c1"&gt;// return intermediate + result&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="c1"&gt;// }&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;The &lt;code&gt;processData&lt;/code&gt; function was called twice with identical arguments, but this duplication was hidden inside &lt;code&gt;transform&lt;/code&gt; and &lt;code&gt;combine&lt;/code&gt;. AI didn&amp;rsquo;t track that the result could be reused and generated similar code in different functions. But this was just the tip of the iceberg.&lt;/p&gt;
&lt;p&gt;Digging deeper, I found:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Functions with 15-20 parameters, half of which were passed straight through&lt;/li&gt;
&lt;li&gt;Circular dependencies between packages hidden through interfaces&lt;/li&gt;
&lt;li&gt;Duplication of business logic in three different places with slight variations&lt;/li&gt;
&lt;li&gt;God objects that knew about the entire system&lt;/li&gt;
&lt;li&gt;Layers of abstractions that abstracted nothing but only complicated the code&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Code became unmaintainable.&lt;/strong&gt; After two weeks, the project turned into what&amp;rsquo;s hard to call anything other than a mess. Adding new functionality required more and more time. AI proposed solutions that worked but further tangled the architecture. Every change pulled a chain of other changes in unexpected places.&lt;/p&gt;
&lt;p&gt;I got tired of creating projects that live two weeks and then become legacy. These were my own pet projects that I did for fun. I&amp;rsquo;m not even talking about production systems - that&amp;rsquo;s completely unacceptable there. I wanted to do development and product growth, not archaeological digs in my own code.&lt;/p&gt;
&lt;h3 id="stop-and-understand"&gt;Stop and Understand
&lt;/h3&gt;&lt;p&gt;I made a decision: stop generating new projects doomed to become unmaintainable and systematically understand the problem. Shifted focus from code generation to research work.&lt;/p&gt;
&lt;p&gt;The main research question: &lt;strong&gt;how to develop projects with AI agents so they remain evolvable and maintainable?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;After analyzing the problem, I came to a key conclusion: vibe coding without formal architecture control is a dead end. AI agents excellently generate code that works here and now. But they don&amp;rsquo;t see the big picture of architecture, don&amp;rsquo;t track accumulation of technical debt, don&amp;rsquo;t notice emerging anti-patterns.&lt;/p&gt;
&lt;p&gt;An engineering approach is needed: formal architecture description, automatic validation, quality metrics. Architecture must be explicit, verifiable, controlled. Only this way can codebase degradation be prevented.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m starting a series of articles on architecture control research, viewing it as a graph data structure. In this first article, I&amp;rsquo;ll show how to automatically build two types of architectural graphs: structural (static) and behavioral (dynamic). All examples are based on a real project &lt;a class="link" href="https://github.com/mshogin/archlint" target="_blank" rel="noopener"
&gt;archlint&lt;/a&gt; - a tool for automatic construction and validation of architectural graphs that I&amp;rsquo;m developing during the research.&lt;/p&gt;
&lt;p&gt;In subsequent articles of the series, I&amp;rsquo;ll cover validation of architectural rules and code quality metrics based on graph theory.&lt;/p&gt;
&lt;h2 id="structural-architecture-static-system-graph"&gt;Structural Architecture: Static System Graph
&lt;/h2&gt;&lt;p&gt;When we talk about software system architecture, we often mean its structure: what components the system consists of, how they&amp;rsquo;re organized, how they&amp;rsquo;re connected to each other. Structural architecture is a static picture capturing potential connections between code elements.&lt;/p&gt;
&lt;h3 id="why-a-formal-structure-model-is-needed"&gt;Why a Formal Structure Model is Needed
&lt;/h3&gt;&lt;p&gt;In traditional development, structural architecture exists as diagrams in documentation, team conventions, knowledge in experienced developers&amp;rsquo; heads. This suffices when code is written by people who understand context and keep the big picture in mind.&lt;/p&gt;
&lt;p&gt;With AI agents, the situation is different. An agent works in limited context, has no global system vision, doesn&amp;rsquo;t remember architectural decisions made a week ago. Each time generating code, it sees only a fragment of the system in the context window.&lt;/p&gt;
&lt;p&gt;The result is predictable: architecture degrades. Circular dependencies appear, code duplication, layered structure breaks. Informal conventions don&amp;rsquo;t work - there&amp;rsquo;s no one to follow them.&lt;/p&gt;
&lt;p&gt;Formal solution: make architecture explicit, automatically verifiable. A mathematical model is needed that accurately describes system structure and allows automatic validation of its correctness.&lt;/p&gt;
&lt;h3 id="graph-as-a-formal-model"&gt;Graph as a Formal Model
&lt;/h3&gt;&lt;p&gt;Structural architecture can be represented through a mathematical abstraction - a directed graph G = (V, E), where:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;V (vertices)&lt;/strong&gt; - set of nodes representing system components&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;E (edges)&lt;/strong&gt; - set of edges representing connections between components&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Each node v ∈ V has:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;id&lt;/strong&gt; - unique identifier (e.g., full package or function name)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;type&lt;/strong&gt; - component type (package, struct, function, method, interface)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;properties&lt;/strong&gt; - additional properties (filename, code line, visibility)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Each edge e ∈ E has:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;from&lt;/strong&gt; - source node&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;to&lt;/strong&gt; - target node&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;type&lt;/strong&gt; - connection semantics (contains, calls, uses, imports, embeds)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This simple model turns out powerful enough to describe real systems. The graph allows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Visualizing&lt;/strong&gt; architecture at different abstraction levels&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Validating&lt;/strong&gt; architectural rules (e.g., &amp;ldquo;UI layer must not depend on DB layer&amp;rdquo;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Computing metrics&lt;/strong&gt; (connectivity, cyclomatic complexity, dependency depth)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tracking changes&lt;/strong&gt; over time&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="real-example-archlint-architecture"&gt;Real Example: archlint Architecture
&lt;/h3&gt;&lt;p&gt;Let&amp;rsquo;s examine the structural architecture of a real project - archlint. This is a tool for building and analyzing architectural graphs, written in Go. Let&amp;rsquo;s see how its structure looks as a graph.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Package Level (8 packages):&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;span class="lnt"&gt;8
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cmd/archlint - main binary for architecture collection
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cmd/tracelint - linter for checking tracing coverage
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;internal/analyzer - Go source code analysis via AST
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;internal/model - architecture graph model
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;internal/cli - CLI commands implementation
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;internal/linter - tracing correctness validation
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pkg/tracer - execution tracing library
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;tests/testdata/sample - test examples with instrumentation
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Organization in &lt;code&gt;internal/&lt;/code&gt; vs &lt;code&gt;pkg/&lt;/code&gt; follows standard Go conventions: &lt;code&gt;internal&lt;/code&gt; contains private packages used only inside the project, &lt;code&gt;pkg&lt;/code&gt; - public libraries that other projects can use.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Data Types:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Data types are organized by domains:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// Graph model&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nx"&gt;internal&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Graph&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;architectural&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;graph&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;representation&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nx"&gt;internal&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Node&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;graph&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;node&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;system&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nx"&gt;internal&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Edge&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;graph&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;edge&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;between&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;components&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="c1"&gt;// Source code analyzer&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nx"&gt;internal&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;analyzer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GoAnalyzer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Go&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;analyzer&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nx"&gt;internal&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;analyzer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PackageInfo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;information&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nx"&gt;internal&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;analyzer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TypeInfo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;information&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nx"&gt;internal&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;analyzer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FunctionInfo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;information&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nx"&gt;internal&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;analyzer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MethodInfo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;information&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nx"&gt;internal&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;analyzer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FieldInfo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;field&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;information&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nx"&gt;internal&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;analyzer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CallInfo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;call&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;information&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="c1"&gt;// Execution tracing&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nx"&gt;pkg&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;tracer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Trace&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;execution&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tracing&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nx"&gt;pkg&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;tracer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Call&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;individual&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;call&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;trace&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nx"&gt;pkg&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;tracer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Context&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;execution&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;context&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;calls&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nx"&gt;pkg&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;tracer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SequenceDiagram&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;sequence&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;diagram&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;trace&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nx"&gt;pkg&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;tracer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SequenceCall&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;call&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;sequence&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;diagram&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nx"&gt;pkg&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;tracer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;UMLConfig&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;configuration&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;UML&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;generation&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Functions:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Functionality is distributed across packages according to single responsibility principle. For example, in &lt;code&gt;internal/cli&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;Internal&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;cli&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Execute&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;CLI&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;point&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nx"&gt;internal&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;cli&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;saveGraph&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;save&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;graph&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nx"&gt;internal&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;cli&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;saveContexts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;save&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;contexts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nx"&gt;internal&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;cli&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;printContextsInfo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;print&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;contexts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;information&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="nx"&gt;internal&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;cli&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;runTrace&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;execute&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;trace&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;command&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Connections Between Components:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The connection graph shows dependencies between packages and data types:&lt;/p&gt;
&lt;div class="mermaid"&gt;
graph TB
cmdArchlint[cmd/archlint&lt;br/&gt;main binary]
cmdTracelint[cmd/tracelint&lt;br/&gt;linter binary]
analyzer[internal/analyzer&lt;br/&gt;code analysis]
model[internal/model&lt;br/&gt;graph model]
cli[internal/cli&lt;br/&gt;CLI commands]
linter[internal/linter&lt;br/&gt;trace validation]
tracer[pkg/tracer&lt;br/&gt;tracing library]
cmdArchlint --&gt;|uses| cli
cmdTracelint --&gt;|uses| linter
cli --&gt;|uses| analyzer
cli --&gt;|uses| tracer
analyzer --&gt;|produces| model
tracer --&gt;|uses| model
linter --&gt;|uses| tracer
style cmdArchlint fill:#e1f5ff
style cmdTracelint fill:#e1f5ff
style analyzer fill:#fff4e1
style model fill:#f0f0f0
style tracer fill:#d4edda
&lt;/div&gt;
&lt;p&gt;This diagram shows high-level architecture. We can see that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Two binaries (&lt;code&gt;cmd/archlint&lt;/code&gt; and &lt;code&gt;cmd/tracelint&lt;/code&gt;) use different subsystems&lt;/li&gt;
&lt;li&gt;The analyzer doesn&amp;rsquo;t depend on CLI, can be used independently&lt;/li&gt;
&lt;li&gt;The graph model (&lt;code&gt;internal/model&lt;/code&gt;) is the central data structure&lt;/li&gt;
&lt;li&gt;Tracer is a public library (&lt;code&gt;pkg/tracer&lt;/code&gt;) that other projects can use&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="automatic-graph-building-from-source-code"&gt;Automatic Graph Building from Source Code
&lt;/h3&gt;&lt;p&gt;Theoretical model is good, but automation is needed. Manually describing a graph of hundreds of components and connections is unrealistic. Moreover, the graph must automatically update with every code change.&lt;/p&gt;
&lt;p&gt;Building the structural graph happens in four stages:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Stage 1: Source Code Analysis&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Using the standard &lt;code&gt;go/ast&lt;/code&gt; package, we go through all project files and build an abstract syntax tree (AST). AST gives complete information about code structure: packages, imports, types, functions, methods, calls.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ archlint collect . -o architecture.yaml
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;The command recursively analyzes all &lt;code&gt;.go&lt;/code&gt; files in the current directory and its subdirectories.&lt;/p&gt;
&lt;p&gt;Analysis result:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;span class="lnt"&gt;8
&lt;/span&gt;&lt;span class="lnt"&gt;9
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Analyzing code: . (language: go)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Found components: 134
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - package: 8 # top-level packages
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - struct: 18 # data structures
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - type: 1 # type aliases
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - function: 55 # regular functions
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - method: 28 # struct methods
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - external: 24 # external dependencies
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Found links: 189
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Important point: external dependencies are also accounted for. These are packages from Go standard library and third-party modules used by the project. The complete dependency picture includes them.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Stage 2: Graph Node Formation&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Each found component becomes a graph node. Nodes have a hierarchical identifier structure:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;components&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;internal/analyzer&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;analyzer&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;package&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;internal/analyzer.GoAnalyzer&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;GoAnalyzer&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;struct&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;internal/analyzer.GoAnalyzer.Analyze&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Analyze&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;method&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;The identifier follows Go conventions: &lt;code&gt;package.Type.Method&lt;/code&gt;. This allows unambiguous identification of any system component.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Stage 3: Graph Edge Formation&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;We create edges expressing connection semantics between components:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;links&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# Package contains type&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;internal/analyzer&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;internal/analyzer.GoAnalyzer&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;contains&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# Type contains method&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;internal/analyzer.GoAnalyzer&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;internal/analyzer.GoAnalyzer.Analyze&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;contains&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# Function calls another function&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;internal/cli.Execute&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;internal/analyzer.NewGoAnalyzer&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;calls&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# Package imports another package&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;cmd/archlint&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;internal/cli&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;imports&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Different edge types allow distinguishing connection semantics:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;contains&lt;/code&gt; - ownership relationship (package contains type, type contains method)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;calls&lt;/code&gt; - function or method call&lt;/li&gt;
&lt;li&gt;&lt;code&gt;uses&lt;/code&gt; - type usage (e.g., in function signature or struct field)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;imports&lt;/code&gt; - package import&lt;/li&gt;
&lt;li&gt;&lt;code&gt;embeds&lt;/code&gt; - type embedding (embedding in Go)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Stage 4: Saving in YAML Format&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The output is a complete system graph in YAML format. This file can be:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Visualized:&lt;/strong&gt; Generate diagrams using PlantUML, Graphviz, or web interfaces like DocHub.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Validated:&lt;/strong&gt; Check architectural rules. For example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&amp;ldquo;Package &lt;code&gt;internal/model&lt;/code&gt; must not depend on anything except standard library&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Circular dependencies between packages are forbidden&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Maximum call nesting depth is 5 levels&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Analyzed:&lt;/strong&gt; Compute metrics:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Graph connectivity (how many components are connected)&lt;/li&gt;
&lt;li&gt;Cyclomatic complexity&lt;/li&gt;
&lt;li&gt;Dependency tree depth&lt;/li&gt;
&lt;li&gt;Coupling and cohesion metrics&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Track changes:&lt;/strong&gt; Compare graph versions, see architecture evolution over time.&lt;/p&gt;
&lt;p&gt;The structural graph of archlint is a complete, formal description of the system&amp;rsquo;s static structure that automatically updates and can be checked with every commit.&lt;/p&gt;
&lt;h2 id="behavioral-architecture-dynamic-execution-graph"&gt;Behavioral Architecture: Dynamic Execution Graph
&lt;/h2&gt;&lt;p&gt;Structural architecture shows what the system can do - all potential execution paths. But it doesn&amp;rsquo;t answer the question: what does the system actually do? Which components are used in specific scenarios? How does data flow through the system?&lt;/p&gt;
&lt;p&gt;To answer these questions, behavioral architecture is needed - a dynamic picture of system execution.&lt;/p&gt;
&lt;h3 id="why-behavioral-architecture-is-needed"&gt;Why Behavioral Architecture is Needed
&lt;/h3&gt;&lt;p&gt;Imagine a large system with a structural graph of thousands of components. You&amp;rsquo;re adding a new feature. Which components are actually used? What execution paths does a request take?&lt;/p&gt;
&lt;p&gt;Without behavioral architecture, you can only guess by reading code. With it - you see the exact sequence of calls built from actual execution.&lt;/p&gt;
&lt;p&gt;Behavioral architecture is critically important for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Understanding complex scenarios&lt;/strong&gt; - seeing the sequence of actions&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Performance optimization&lt;/strong&gt; - finding bottlenecks in real execution paths&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Identifying dead code&lt;/strong&gt; - functions that aren&amp;rsquo;t called in any scenario&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Documentation&lt;/strong&gt; - automatic sequence diagrams instead of manual drawing&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Coverage control&lt;/strong&gt; - which business scenarios are covered by acceptance tests&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="how-acceptance-tests-form-behavioral-architecture"&gt;How Acceptance Tests Form Behavioral Architecture
&lt;/h3&gt;&lt;p&gt;Key idea: behavioral architecture isn&amp;rsquo;t invented abstractly - it&amp;rsquo;s extracted from real executable code. The source is acceptance tests.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The &amp;ldquo;one task - one acceptance test&amp;rdquo; principle:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;With proper work decomposition, each task has an acceptance test that verifies implementation correctness. An acceptance test describes a specific system usage scenario - it defines an &lt;strong&gt;execution context&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Task &amp;ldquo;Calculator with Memory&amp;rdquo; -&amp;gt; acceptance test &lt;code&gt;TestCalculateWithMemory&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Task &amp;ldquo;Export Report to PDF&amp;rdquo; -&amp;gt; acceptance test &lt;code&gt;TestExportReportToPDF&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Task &amp;ldquo;OAuth Authorization&amp;rdquo; -&amp;gt; acceptance test &lt;code&gt;TestOAuthLogin&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Each such test defines a separate context - an isolated system usage scenario.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Behavioral graph building process:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="mermaid"&gt;
flowchart LR
feature[Feature:&lt;br/&gt;Calculate with Memory]
test[Acceptance Test:&lt;br/&gt;TestCalculateWithMemory]
trace[Trace File:&lt;br/&gt;test_calculate.json]
seq[Sequence Diagram:&lt;br/&gt;PlantUML]
behgraph[Behavioral Graph:&lt;br/&gt;Numbered Edges]
context[Context:&lt;br/&gt;CalculateWithMemory]
feature --&gt; test
test --&gt; trace
trace --&gt; seq
trace --&gt; behgraph
seq --&gt; context
behgraph --&gt; context
style feature fill:#e1f5ff
style test fill:#fff4e1
style trace fill:#f0f0f0
style context fill:#d4edda
&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Feature&lt;/strong&gt; - business requirement or task&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Acceptance test&lt;/strong&gt; - code verifying the feature&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Trace&lt;/strong&gt; - complete call sequence during test execution&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sequence diagram&lt;/strong&gt; - visualization of interaction sequence&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Behavioral graph&lt;/strong&gt; - graph with numbered edges&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Context&lt;/strong&gt; - formalized feature execution context&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="real-example-calculate-with-trace-context"&gt;Real Example: &amp;ldquo;Calculate With Trace&amp;rdquo; Context
&lt;/h3&gt;&lt;p&gt;Let&amp;rsquo;s examine a real acceptance test from the archlint project:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;TestCalculateWithTrace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;testing&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// Create directory for traces&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;traceDir&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;traces&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MkdirAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;traceDir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mo"&gt;0755&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// Start tracing&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;trace&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tracer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;StartTrace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;TestCalculateWithTrace&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;defer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;trace&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tracer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;StopTrace&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;trace&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;trace&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filepath&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;traceDir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;test_calculate.json&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// Execute acceptance test scenario&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;calc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;NewCalculator&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// create calculator&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;calc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Calculate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// calculate (5 + 3) * 2 = 16&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// Check acceptance criterion&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Expected 16, got %d&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;The test looks like a regular Go test but with tracing added. &lt;code&gt;tracer.StartTrace&lt;/code&gt; and &lt;code&gt;tracer.StopTrace&lt;/code&gt; wrap scenario execution.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Code Instrumentation:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;All system functions contain instrumentation points:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;span class="lnt"&gt;25
&lt;/span&gt;&lt;span class="lnt"&gt;26
&lt;/span&gt;&lt;span class="lnt"&gt;27
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;NewCalculator&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Calculator&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tracer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Enter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;sample.NewCalculator&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;defer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tracer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ExitSuccess&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;sample.NewCalculator&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;Calculator&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;memory&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Calculator&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;Calculate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tracer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Enter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;sample.Calculator.Calculate&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;defer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tracer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ExitSuccess&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;sample.Calculator.Calculate&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;sum&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// trace will record the call&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;Multiply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// trace will record the call&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddToMemory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// trace will record the call&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetMemory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// trace will record the call&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tracer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Enter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;sample.Add&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;defer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tracer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ExitSuccess&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;sample.Add&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;Multiply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tracer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Enter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;sample.Multiply&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;defer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tracer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ExitSuccess&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;sample.Multiply&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Instrumentation is minimal: &lt;code&gt;tracer.Enter&lt;/code&gt; at function start, &lt;code&gt;tracer.ExitSuccess&lt;/code&gt; at end (via defer). This doesn&amp;rsquo;t affect logic, only records the fact of the call.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tracing Result:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;After test execution, we get a JSON file with the complete sequence of all calls:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;span class="lnt"&gt;25
&lt;/span&gt;&lt;span class="lnt"&gt;26
&lt;/span&gt;&lt;span class="lnt"&gt;27
&lt;/span&gt;&lt;span class="lnt"&gt;28
&lt;/span&gt;&lt;span class="lnt"&gt;29
&lt;/span&gt;&lt;span class="lnt"&gt;30
&lt;/span&gt;&lt;span class="lnt"&gt;31
&lt;/span&gt;&lt;span class="lnt"&gt;32
&lt;/span&gt;&lt;span class="lnt"&gt;33
&lt;/span&gt;&lt;span class="lnt"&gt;34
&lt;/span&gt;&lt;span class="lnt"&gt;35
&lt;/span&gt;&lt;span class="lnt"&gt;36
&lt;/span&gt;&lt;span class="lnt"&gt;37
&lt;/span&gt;&lt;span class="lnt"&gt;38
&lt;/span&gt;&lt;span class="lnt"&gt;39
&lt;/span&gt;&lt;span class="lnt"&gt;40
&lt;/span&gt;&lt;span class="lnt"&gt;41
&lt;/span&gt;&lt;span class="lnt"&gt;42
&lt;/span&gt;&lt;span class="lnt"&gt;43
&lt;/span&gt;&lt;span class="lnt"&gt;44
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;test_name&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;TestCalculateWithTrace&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;start_time&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;2025-12-07T21:33:05.550942+03:00&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;end_time&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;2025-12-07T21:33:05.550946+03:00&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;calls&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;event&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;enter&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;function&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;sample.NewCalculator&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;timestamp&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;2025-12-07T21:33:05.550942+03:00&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;depth&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;event&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;exit_success&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;function&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;sample.NewCalculator&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;timestamp&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;2025-12-07T21:33:05.550942+03:00&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;depth&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;event&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;enter&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;function&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;sample.Calculator.Calculate&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;timestamp&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;2025-12-07T21:33:05.550942+03:00&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;depth&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;event&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;enter&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;function&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;sample.Add&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;timestamp&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;2025-12-07T21:33:05.550943+03:00&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;depth&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;event&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;exit_success&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;function&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;sample.Add&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;timestamp&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;2025-12-07T21:33:05.550943+03:00&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;depth&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;event&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;enter&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;function&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;sample.Multiply&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;timestamp&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;2025-12-07T21:33:05.550943+03:00&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;depth&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="err"&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Each event contains:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;event&lt;/code&gt; - event type (enter/exit_success/exit_error)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;function&lt;/code&gt; - full function name&lt;/li&gt;
&lt;li&gt;&lt;code&gt;timestamp&lt;/code&gt; - exact call time&lt;/li&gt;
&lt;li&gt;&lt;code&gt;depth&lt;/code&gt; - nesting level (0 = top-level, 1 = first call, etc.)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;code&gt;depth&lt;/code&gt; field allows reconstructing the call hierarchy: which function was called from which.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Automatic Context Generation:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A context is automatically generated from the trace file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ archlint trace ./traces -o contexts.yaml
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Result - formal context description in YAML:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;contexts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;tests.testcalculatewithtrace&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Calculate With Trace&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;location&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Tests/Calculate With Trace&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;presentation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;plantuml&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;components&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;sample.new_calculator&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;sample.calculator.calculate&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;sample.add&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;sample.multiply&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;sample.calculator.add_to_memory&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;sample.calculator.get_memory&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;uml&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;output/traces/test_calculate.puml&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;The context includes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;title&lt;/strong&gt; - human-readable name&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;location&lt;/strong&gt; - place in context hierarchy&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;components&lt;/strong&gt; - list of all components participating in the scenario&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;uml.file&lt;/strong&gt; - path to automatically generated PlantUML diagram&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="visualizations-sequence-diagram-and-graph"&gt;Visualizations: Sequence Diagram and Graph
&lt;/h3&gt;&lt;p&gt;From one trace, two different representations can be obtained: a sequence diagram and a behavioral graph.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Sequence diagram&lt;/strong&gt; shows the sequence of interactions between components over time:&lt;/p&gt;
&lt;div class="mermaid"&gt;
sequenceDiagram
participant Test
participant Calculator
participant Add
participant Multiply
participant Memory
Test-&gt;&gt;Calculator: Calculate(5, 3)
Calculator-&gt;&gt;Add: Add(5, 3)
Add--&gt;&gt;Calculator: 8
Calculator-&gt;&gt;Multiply: Multiply(8, 2)
Multiply--&gt;&gt;Calculator: 16
Calculator-&gt;&gt;Memory: AddToMemory(16)
Calculator-&gt;&gt;Memory: GetMemory()
Memory--&gt;&gt;Calculator: 16
Calculator--&gt;&gt;Test: 16
&lt;/div&gt;
&lt;p&gt;The sequence diagram is convenient for understanding the sequence of actions: who calls whom, in what order, what data is passed. This is a classic UML representation familiar to all developers.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Behavioral graph&lt;/strong&gt; represents the same data as a graph with numbered edges:&lt;/p&gt;
&lt;div class="mermaid"&gt;
graph TD
test[TestCalculateWithTrace]
newCalc[NewCalculator]
calc[Calculator.Calculate]
add[Add]
mult[Multiply]
addMem[AddToMemory]
getMem[GetMemory]
test --&gt;|1| newCalc
test --&gt;|2| calc
calc --&gt;|3| add
calc --&gt;|4| mult
calc --&gt;|5| addMem
calc --&gt;|6| getMem
style test fill:#e1f5ff
style calc fill:#fff4e1
style add fill:#f0f0f0
style mult fill:#f0f0f0
&lt;/div&gt;
&lt;p&gt;The graph is more compact than the sequence diagram and better suited for analysis. Numbers on edges show call order.&lt;/p&gt;
&lt;p&gt;Key features of the behavioral graph:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Edges are numbered&lt;/strong&gt; - execution order is preserved&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Multigraph&lt;/strong&gt; - there can be multiple edges between two nodes (if the function was called multiple times)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Context-dependent&lt;/strong&gt; - shows a specific scenario, not all possible paths&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Subgraph of structural graph&lt;/strong&gt; - each behavioral graph node exists in the structural graph&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="behavioral-architecture-coverage-metrics"&gt;Behavioral Architecture Coverage Metrics
&lt;/h3&gt;&lt;p&gt;Acceptance tests directly determine the completeness of behavioral architecture. Each acceptance test creates one context. The totality of all contexts is the complete behavioral architecture of the system.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Key metrics:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Component coverage:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;coverage = (called components) / (total components) * 100%
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;For example, if the structural graph has N components and M components are called in acceptance tests, then coverage = M/N * 100%.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Number of contexts:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The more acceptance tests, the more contexts, the more complete coverage of different usage scenarios.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Critical path coverage:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Not all components are equally important. Critical business scenarios can be marked and their coverage tracked separately.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Dead code detection:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If a component is present in the structural graph but doesn&amp;rsquo;t appear in any context - it&amp;rsquo;s a candidate for removal. Either the code is dead or acceptance tests are lacking.&lt;/p&gt;
&lt;p&gt;In a real project, aim for 80%+ coverage of critical paths with acceptance tests.&lt;/p&gt;
&lt;h2 id="conclusion-two-views-of-architecture"&gt;Conclusion: Two Views of Architecture
&lt;/h2&gt;&lt;p&gt;In this article, I showed how to represent software system architecture through a graph data structure. Two types of graphs provide two different but complementary views of the system:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Structural graph&lt;/strong&gt; shows how code is organized: what components exist and how they can interact. This is a static picture of potential connections. Construction is automated through AST analysis of source code.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Behavioral graph&lt;/strong&gt; shows how the system actually works: which components are called in specific scenarios and in what sequence. This is a dynamic picture of actual execution paths. Construction is automated through acceptance test tracing.&lt;/p&gt;
&lt;p&gt;Key difference: the structural graph contains ALL possible connections, behavioral - only those actually used in business scenarios.&lt;/p&gt;
&lt;h3 id="whats-next"&gt;What&amp;rsquo;s Next
&lt;/h3&gt;&lt;p&gt;Graphs themselves are just the foundation. The interesting part begins when we use them for architecture quality control.&lt;/p&gt;
&lt;p&gt;In subsequent articles of the series, I&amp;rsquo;ll show:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Validation of architectural rules&lt;/strong&gt; - how to check graph constraints: prohibition of circular dependencies, layered architecture control, call depth limits&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Graph theory metrics&lt;/strong&gt; - how to measure architecture quality through connectivity, centrality, modularity and other metrics&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AI-generated code control&lt;/strong&gt; - how to use graphs and metrics to prevent architectural degradation when developing with AI agents&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="tools"&gt;Tools
&lt;/h3&gt;&lt;p&gt;All tools for building architectural graphs are available in the open repository: &lt;a class="link" href="https://github.com/mshogin/archlint" target="_blank" rel="noopener"
&gt;github.com/mshogin/archlint&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The tool works with Go projects, but the approach is universal and applicable to any programming language.&lt;/p&gt;
&lt;p&gt;The project includes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Go code analyzer for building structural graphs&lt;/li&gt;
&lt;li&gt;Tracing library for building behavioral graphs&lt;/li&gt;
&lt;li&gt;Visualization generators (PlantUML, Mermaid)&lt;/li&gt;
&lt;li&gt;CI/CD integration examples&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Working with Chaos in Architecture</title><link>https://mshogin.com/blog/working-with-chaos/</link><pubDate>Mon, 28 Apr 2025 00:00:00 +0000</pubDate><guid>https://mshogin.com/blog/working-with-chaos/</guid><description>&lt;img src="https://mshogin.com/blog/working-with-chaos/cover.en.svg" alt="Featured image of post Working with Chaos in Architecture" /&gt;&lt;p&gt;When you work with real systems, you quickly realize: most of the time you don&amp;rsquo;t start with a clean slate.&lt;/p&gt;
&lt;p&gt;You start with history, compromises, half-implemented ideas, and changing priorities.&lt;/p&gt;
&lt;p&gt;At first, it feels messy. But over time, you learn something important: clarity isn&amp;rsquo;t given - it&amp;rsquo;s created.&lt;/p&gt;
&lt;h2 id="what-working-with-chaotic-architectures-taught-me"&gt;What working with chaotic architectures taught me
&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Listen before judging.&lt;/strong&gt; Every decision was made in a certain context. Understanding that context is more important than rushing to conclusions.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Find patterns without forcing them.&lt;/strong&gt; Patterns exist almost everywhere, but you need to let them emerge rather than forcing their appearance.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Build small anchors in unstable ground.&lt;/strong&gt; When there&amp;rsquo;s a lot of uncertainty around, small steady steps are important.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;And most importantly - stay patient with complexity.&lt;/strong&gt; Complexity is not the enemy. It&amp;rsquo;s reality that you need to learn to work with.&lt;/p&gt;
&lt;h2 id="every-messy-system-holds-a-story"&gt;Every messy system holds a story
&lt;/h2&gt;&lt;p&gt;And architecture, at its best, is about understanding that story and helping write the next chapter a little better.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re also working in the middle of chaos: you&amp;rsquo;re not doing it wrong. Most likely, you&amp;rsquo;re exactly where real architecture starts.&lt;/p&gt;</description></item></channel></rss>