-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcontext-graph.html
More file actions
216 lines (194 loc) · 14.3 KB
/
context-graph.html
File metadata and controls
216 lines (194 loc) · 14.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>The Context Graph — Why agents need to know WHY</title>
<style>
:root {
--bg: #ffffff;
--bg2: #f5f4f0;
--text: #1a1a18;
--text2: #5f5e5a;
--text3: #888780;
--border: rgba(0,0,0,0.12);
--border2: rgba(0,0,0,0.22);
--purple50: #EEEDFE; --purple200: #AFA9EC; --purple600: #534AB7; --purple800: #3C3489;
--blue50: #E6F1FB; --blue200: #85B7EB; --blue600: #185FA5; --blue800: #0C447C;
--teal50: #E1F5EE; --teal200: #5DCAA5; --teal600: #0F6E56; --teal800: #085041;
--amber50: #FAEEDA; --amber200: #EF9F27; --amber600: #854F0B; --amber800: #633806;
--coral50: #FAECE7; --coral200: #F0997B; --coral600: #993C1D; --coral800: #712B13;
--gray50: #F1EFE8; --gray200: #B4B2A9; --gray600: #5F5E5A; --gray800: #444441;
}
@media (prefers-color-scheme: dark) {
:root {
--bg: #1c1c1a; --bg2: #252522;
--text: #e8e6de; --text2: #a8a69e; --text3: #6e6c65;
--border: rgba(255,255,255,0.1); --border2: rgba(255,255,255,0.2);
--purple50: #26215C; --purple200: #3C3489; --purple600: #AFA9EC; --purple800: #CECBF6;
--blue50: #042C53; --blue200: #0C447C; --blue600: #85B7EB; --blue800: #B5D4F4;
--teal50: #04342C; --teal200: #085041; --teal600: #5DCAA5; --teal800: #9FE1CB;
--amber50: #412402; --amber200: #633806; --amber600: #EF9F27; --amber800: #FAC775;
--coral50: #4A1B0C; --coral200: #712B13; --coral600: #F0997B; --coral800: #F5C4B3;
--gray50: #2C2C2A; --gray200: #444441; --gray600: #B4B2A9; --gray800: #D3D1C7;
}
}
* { box-sizing: border-box; margin: 0; padding: 0; }
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; background: var(--bg); color: var(--text); line-height: 1.6; }
.wrap { max-width: 760px; margin: 0 auto; padding: 48px 24px 80px; }
.eyebrow { font-size: 12px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--text3); margin-bottom: 12px; }
h1 { font-size: 28px; font-weight: 500; line-height: 1.25; margin-bottom: 12px; }
.sub { font-size: 16px; color: var(--text2); margin-bottom: 36px; max-width: 580px; line-height: 1.65; }
.tabs { display: flex; gap: 8px; margin-bottom: 20px; }
.tab {
padding: 7px 20px; font-size: 13px; font-family: inherit;
border-radius: 8px; border: 0.5px solid var(--border2);
background: transparent; color: var(--text2);
cursor: pointer; transition: all 0.18s;
}
.tab.on { background: var(--bg2); color: var(--text); border-color: var(--border2); }
.viz { background: var(--bg2); border-radius: 12px; padding: 24px 20px 20px; border: 0.5px solid var(--border); }
svg { display: block; width: 100%; }
@keyframes edgeDraw { from { stroke-dashoffset: 200; } to { stroke-dashoffset: 0; } }
.e { stroke-dasharray: 200; stroke-dashoffset: 200; opacity: 0; }
.e.show { opacity: 1; animation: edgeDraw 0.65s ease forwards; }
.pni { transition: opacity 0.4s; }
.note {
margin-top: 16px; font-size: 14px; line-height: 1.65; color: var(--text2);
border-left: 2px solid var(--border2); padding: 10px 16px;
border-radius: 0 6px 6px 0; background: var(--bg);
}
.note strong { color: var(--text); font-weight: 500; }
.divider { border: none; border-top: 0.5px solid var(--border); margin: 48px 0; }
.section-label { font-size: 13px; color: var(--text3); text-transform: uppercase; letter-spacing: 0.07em; margin-bottom: 8px; }
p { font-size: 15px; color: var(--text2); line-height: 1.75; margin-bottom: 16px; }
.prop-list { margin: 0 0 16px 0; padding: 0; list-style: none; }
.prop-list li { font-size: 15px; color: var(--text2); line-height: 1.75; padding: 6px 0 6px 20px; position: relative; border-bottom: 0.5px solid var(--border); }
.prop-list li:last-child { border-bottom: none; }
.prop-list li::before { content: "—"; position: absolute; left: 0; color: var(--text3); }
.prop-list li strong { color: var(--text); font-weight: 500; }
.callout { background: var(--bg2); border-radius: 8px; padding: 16px 20px; margin-bottom: 16px; border: 0.5px solid var(--border); }
.callout p { margin-bottom: 0; font-size: 15px; }
.footer { margin-top: 56px; font-size: 12px; color: var(--text3); }
.footer a { color: var(--text3); }
</style>
</head>
<body>
<div class="wrap">
<div class="eyebrow">GitHub · Agent Infrastructure · 2026</div>
<h1>Nodes vs. edges: what agents lose without the context graph</h1>
<p class="sub">Any AI agent can read the assets in a codebase. The question is whether the evidence connecting them is stored somewhere — and whether that record can survive a regulatory audit.</p>
<div class="viz">
<div class="tabs">
<button class="tab" id="t1" onclick="go('off')">Without GitHub graph</button>
<button class="tab on" id="t2" onclick="go('on')">With GitHub context graph</button>
</div>
<svg viewBox="0 0 680 440">
<defs>
<marker id="ar" viewBox="0 0 10 10" refX="8" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
<path d="M2 1L8 5L2 9" fill="none" stroke="context-stroke" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</marker>
</defs>
<line id="e1" class="e" x1="340" y1="116" x2="340" y2="204" stroke="var(--purple600)" stroke-width="1.5" marker-end="url(#ar)"/>
<line id="e2" class="e" x1="418" y1="192" x2="382" y2="208" stroke="var(--blue600)" stroke-width="1.5" marker-end="url(#ar)"/>
<line id="e3" class="e" x1="382" y1="272" x2="418" y2="288" stroke="var(--teal600)" stroke-width="1.5" marker-end="url(#ar)"/>
<line id="e4" class="e" x1="418" y1="340" x2="382" y2="356" stroke="var(--teal600)" stroke-width="1" marker-end="url(#ar)"/>
<line id="e5" class="e" x1="258" y1="288" x2="298" y2="272" stroke="var(--amber600)" stroke-width="1.5" marker-end="url(#ar)"/>
<line id="e6" class="e" x1="258" y1="192" x2="298" y2="208" stroke="var(--gray600)" stroke-width="1.5" marker-end="url(#ar)"/>
<!-- ISO req -->
<g class="pni" id="pn1">
<rect x="262" y="66" width="156" height="50" rx="8" fill="var(--purple50)" stroke="var(--purple600)" stroke-width="0.5"/>
<text x="340" y="86" text-anchor="middle" dominant-baseline="central" fill="var(--purple800)" font-size="14" font-weight="500" font-family="inherit">ISO 26262 Req</text>
<text x="340" y="104" text-anchor="middle" dominant-baseline="central" fill="var(--purple600)" font-size="12" font-family="inherit">§4.5 safety requirement</text>
</g>
<!-- ADR -->
<g class="pni" id="pn2">
<rect x="432" y="140" width="156" height="50" rx="8" fill="var(--blue50)" stroke="var(--blue600)" stroke-width="0.5"/>
<text x="510" y="160" text-anchor="middle" dominant-baseline="central" fill="var(--blue800)" font-size="14" font-weight="500" font-family="inherit">Arch. Decision</text>
<text x="510" y="178" text-anchor="middle" dominant-baseline="central" fill="var(--blue600)" font-size="12" font-family="inherit">Record ADR-014</text>
</g>
<!-- Central node — the code file -->
<rect x="262" y="208" width="156" height="50" rx="8" fill="var(--blue50)" stroke="var(--blue600)" stroke-width="1.2"/>
<text x="340" y="228" text-anchor="middle" dominant-baseline="central" fill="var(--blue800)" font-size="14" font-weight="500" font-family="inherit">safety_module.c</text>
<text x="340" y="246" text-anchor="middle" dominant-baseline="central" fill="var(--blue600)" font-size="12" font-family="inherit">Safety-critical asset</text>
<!-- Test case -->
<g class="pni" id="pn3">
<rect x="432" y="288" width="156" height="50" rx="8" fill="var(--teal50)" stroke="var(--teal600)" stroke-width="0.5"/>
<text x="510" y="308" text-anchor="middle" dominant-baseline="central" fill="var(--teal800)" font-size="14" font-weight="500" font-family="inherit">Test Case TC-042</text>
<text x="510" y="326" text-anchor="middle" dominant-baseline="central" fill="var(--teal600)" font-size="12" font-family="inherit">Integration test suite</text>
</g>
<!-- Compliance gate -->
<g class="pni" id="pn4">
<rect x="262" y="356" width="156" height="50" rx="8" fill="var(--coral50)" stroke="var(--coral600)" stroke-width="0.5"/>
<text x="340" y="376" text-anchor="middle" dominant-baseline="central" fill="var(--coral800)" font-size="14" font-weight="500" font-family="inherit">Compliance Gate</text>
<text x="340" y="394" text-anchor="middle" dominant-baseline="central" fill="var(--coral600)" font-size="12" font-family="inherit">v2.4 release gate</text>
</g>
<!-- Field issue -->
<g class="pni" id="pn5">
<rect x="92" y="288" width="156" height="50" rx="8" fill="var(--amber50)" stroke="var(--amber600)" stroke-width="0.5"/>
<text x="170" y="308" text-anchor="middle" dominant-baseline="central" fill="var(--amber800)" font-size="14" font-weight="500" font-family="inherit">Field Issue #1337</text>
<text x="170" y="326" text-anchor="middle" dominant-baseline="central" fill="var(--amber600)" font-size="12" font-family="inherit">Customer reported</text>
</g>
<!-- PR -->
<g class="pni" id="pn6">
<rect x="92" y="140" width="156" height="50" rx="8" fill="var(--gray50)" stroke="var(--gray600)" stroke-width="0.5"/>
<text x="170" y="160" text-anchor="middle" dominant-baseline="central" fill="var(--gray800)" font-size="14" font-weight="500" font-family="inherit">Pull Request #892</text>
<text x="170" y="178" text-anchor="middle" dominant-baseline="central" fill="var(--gray600)" font-size="12" font-family="inherit">November 2024</text>
</g>
<text id="slabel" x="340" y="428" text-anchor="middle" fill="var(--text3)" font-size="12" font-family="inherit">6 causal connections stored — evidence chain is complete and auditable</text>
</svg>
<div id="n-on" class="note">GitHub <strong>holds</strong> the evidence: <strong>WHY</strong> the code was written (ISO §4.5), <strong>WHAT</strong> constrains it (ADR-014), <strong>WHAT</strong> validates it (TC-042), <strong>WHAT</strong> gates it (compliance v2.4), and <strong>WHAT</strong> history prompted it (Issue #1337 → PR #892). An AI agent reads this graph — it does not replace it. The record is what survives an audit.</div>
<div id="n-off" class="note" style="display:none">Six related assets. Any agent can read every one of them in isolation. It can reason about the code's logic. But the connections between them — the requirement it satisfies, the field failure that prompted it, the compliance gate it feeds — are not stored anywhere. When an auditor asks for the evidence chain, there is nothing to produce. <em>Reasoning without a record.</em></div>
</div>
<hr class="divider">
<div class="section-label">The argument</div>
<p>Most platforms in the software development lifecycle hold <em>snapshots</em>. GitHub holds <em>causality</em>. Every commit carries a thread: who changed it, when, what issue it was responding to, what decision preceded it, what test it broke or fixed.</p>
<p>Layered over years of a software project, this becomes something a regulated industry cannot afford to lose — an organizational memory that is <em>also</em> a legal record. Not just <em>what</em> the software does, but <em>why</em> it became what it is, with the timestamps and attribution to prove it.</p>
<p>The question an auditor asks under ISO 26262, DO-178C, or IEC 62304 is not "did you run static analysis?" It is: <em>can you produce the evidence that this version of this module was analyzed under these requirements, that the result was a gating condition on this release, and that no step in that chain was altered after the fact?</em></p>
<p>A legally defensible evidence chain has four properties an AI agent cannot supply on its own:</p>
<ul class="prop-list">
<li><strong>Immutability.</strong> Git's SHA-based commit graph is cryptographically tamper-evident. An agent's inference about what probably happened is not.</li>
<li><strong>Attribution.</strong> Every change must be traceable to a named, authorized human. Git carries this natively. A reconstructed graph assembled from inference does not.</li>
<li><strong>Timestamp integrity.</strong> The <em>when</em> must be verifiable. Commit timestamps are part of the hash chain. Anything assembled downstream is derived, not authoritative.</li>
<li><strong>Completeness of the causal chain.</strong> Requirement → Design Decision → Implementation → Test → Gate → Release. GitHub is the only single system where all six exist in one place, connected by native references.</li>
</ul>
<div class="callout">
<p>Any agent can reason about your code. Only one system holds the evidence chain that makes that reasoning auditable.</p>
</div>
<p>The AI model is the reader. GitHub is the record. In regulated industries, that distinction is not architectural preference — it is the difference between passing an audit and failing one.</p>
<div class="footer">
Clay Nelson · GitHub, Worldwide Industry Solutions ·
<a href="https://github.com/claynelson">github.com/claynelson</a>
</div>
</div>
<script>
function go(mode) {
const edges = document.querySelectorAll('.e');
const pnodes = document.querySelectorAll('.pni');
document.getElementById('t1').classList.toggle('on', mode === 'off');
document.getElementById('t2').classList.toggle('on', mode === 'on');
document.getElementById('n-on').style.display = mode === 'on' ? '' : 'none';
document.getElementById('n-off').style.display = mode === 'off' ? '' : 'none';
document.getElementById('slabel').textContent = mode === 'on'
? '6 causal connections stored — evidence chain is complete and auditable'
: 'Agent sees: 6 isolated assets — no stored connections, no evidence chain';
if (mode === 'on') {
pnodes.forEach(n => { n.style.opacity = '1'; });
edges.forEach((e, i) => {
e.classList.remove('show');
e.getBoundingClientRect();
setTimeout(() => e.classList.add('show'), 60 + i * 85);
});
} else {
pnodes.forEach(n => { n.style.opacity = '0.1'; });
edges.forEach(e => e.classList.remove('show'));
}
}
window.addEventListener('load', () => {
document.querySelectorAll('.e').forEach((e, i) => {
setTimeout(() => e.classList.add('show'), 500 + i * 90);
});
});
</script>
</body>
</html>