web-agent-bridge 3.17.0 → 3.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.ar.md +27 -8
- package/README.md +95 -0
- package/bin/wab-init.js +38 -0
- package/package.json +1 -1
- package/public/atp-semantics.html +216 -0
- package/public/benchmarks.html +151 -0
- package/public/docs.html +113 -43
- package/public/index.html +142 -8
- package/public/key-rotation.html +184 -0
- package/public/llms.txt +54 -0
- package/public/notary.html +94 -0
- package/public/observatory.html +103 -0
- package/public/research.html +57 -0
- package/public/researchers.html +113 -0
- package/public/responsible-disclosure.html +294 -0
- package/public/robots.txt +17 -0
- package/public/security.html +157 -0
- package/public/threat-model.html +153 -0
- package/public/viral-coefficient.html +533 -0
- package/public/wab-dataset.html +501 -0
- package/public/wab-email.html +78 -0
- package/public/wab-lens.html +61 -0
- package/public/wab-p2p.html +96 -0
- package/public/wab-registry.html +481 -0
- package/public/wab-today.html +448 -0
- package/public/wab-uri.html +88 -0
- package/script/ai-agent-bridge.js +24 -4
- package/server/index.js +1193 -827
- package/server/models/db.js +2 -1
- package/server/routes/admin-shieldlink.js +1 -1
- package/server/routes/admin-shieldqr.js +1 -1
- package/server/routes/admin-trust-monitor.js +1 -1
- package/server/routes/api-keys.js +2 -1
- package/server/routes/customer-shieldlink.js +1 -1
- package/server/routes/enterprise-mesh.js +2 -1
- package/server/routes/genius-bridge.js +256 -0
- package/server/routes/genius-gateway.js +137 -0
- package/server/routes/governance-saas.js +2 -1
- package/server/routes/notary.js +309 -0
- package/server/routes/observatory.js +109 -0
- package/server/routes/partners.js +2 -1
- package/server/routes/registry.js +352 -0
- package/server/routes/research.js +83 -0
- package/server/routes/ring4.js +2 -1
- package/server/routes/runtime.js +98 -25
- package/server/routes/security-researchers.js +161 -0
- package/server/routes/shieldqr.js +1 -1
- package/server/routes/traces.js +247 -0
- package/server/services/agent-tasks.js +9 -7
- package/server/services/email.js +50 -2
- package/server/services/marketplace.js +27 -8
- package/server/services/plans.js +1 -1
- package/server/services/shieldlink.js +1 -1
- package/server/services/ssl-ct-monitor.js +1 -1
- package/server/services/ssl-monitor.js +1 -1
- package/server/services/stripe.js +29 -4
- package/server/utils/migrate.js +1 -1
- package/server/utils/safe-compare.js +26 -0
|
@@ -0,0 +1,533 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
6
|
+
<title>WAB Viral Coefficient — Self-Propagating Network Mathematics</title>
|
|
7
|
+
<meta name="description" content="Mathematical model of the WAB Spider Network viral coefficient. Live R₀ calculation, k-factor, and critical mass projections.">
|
|
8
|
+
<link rel="icon" href="/assets/favicon.ico">
|
|
9
|
+
<style>
|
|
10
|
+
:root{
|
|
11
|
+
--bg:#0d1117;--panel:#161b22;--border:#30363d;--accent:#58a6ff;--green:#3fb950;
|
|
12
|
+
--amber:#f0883e;--red:#f85149;--purple:#bc8cff;--text:#e6edf3;--muted:#8b949e;
|
|
13
|
+
}
|
|
14
|
+
*{box-sizing:border-box;margin:0;padding:0}
|
|
15
|
+
body{background:var(--bg);color:var(--text);font-family:'Segoe UI',system-ui,sans-serif;min-height:100vh}
|
|
16
|
+
a{color:var(--accent);text-decoration:none}a:hover{text-decoration:underline}
|
|
17
|
+
header{background:var(--panel);border-bottom:1px solid var(--border);padding:14px 24px;display:flex;align-items:center;gap:12px;flex-wrap:wrap}
|
|
18
|
+
header .logo{font-size:1.1rem;font-weight:700}header .logo span{color:var(--green)}
|
|
19
|
+
header .badge{background:#1c3344;color:var(--accent);font-size:.72rem;padding:3px 8px;border-radius:4px;font-weight:600;border:1px solid #264a6e}
|
|
20
|
+
header nav{margin-left:auto;display:flex;gap:18px;font-size:.88rem}
|
|
21
|
+
main{max-width:1100px;margin:0 auto;padding:36px 20px}
|
|
22
|
+
h1{font-size:2rem;font-weight:700;margin-bottom:8px}
|
|
23
|
+
.subtitle{color:var(--muted);font-size:1rem;max-width:720px;line-height:1.6;margin-bottom:36px}
|
|
24
|
+
h2{font-size:1.2rem;font-weight:700;margin-bottom:16px;padding-bottom:8px;border-bottom:1px solid var(--border)}
|
|
25
|
+
section{margin-bottom:48px}
|
|
26
|
+
.panel{background:var(--panel);border:1px solid var(--border);border-radius:10px;padding:24px}
|
|
27
|
+
|
|
28
|
+
/* live KPIs */
|
|
29
|
+
.kpi-row{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:16px;margin-bottom:40px}
|
|
30
|
+
.kpi{background:var(--panel);border:1px solid var(--border);border-radius:10px;padding:20px 24px;text-align:center}
|
|
31
|
+
.kpi .val{font-size:2.2rem;font-weight:700;font-variant-numeric:tabular-nums}
|
|
32
|
+
.kpi .lbl{font-size:.76rem;color:var(--muted);margin-top:4px;text-transform:uppercase;letter-spacing:.05em}
|
|
33
|
+
.kpi.green .val{color:var(--green)}.kpi.blue .val{color:var(--accent)}
|
|
34
|
+
.kpi.amber .val{color:var(--amber)}.kpi.red .val{color:var(--red)}
|
|
35
|
+
.kpi.pulse .val{animation:pulse 2s infinite}
|
|
36
|
+
@keyframes pulse{0%,100%{opacity:1}50%{opacity:.5}}
|
|
37
|
+
|
|
38
|
+
/* R0 indicator */
|
|
39
|
+
.r0-gauge{text-align:center;padding:32px 0;margin-bottom:28px}
|
|
40
|
+
.r0-gauge .r0-value{font-size:5rem;font-weight:900;font-variant-numeric:tabular-nums;letter-spacing:-.04em;transition:color .5s}
|
|
41
|
+
.r0-gauge .r0-label{font-size:.9rem;color:var(--muted);margin-top:6px}
|
|
42
|
+
.r0-gauge .r0-status{display:inline-block;padding:6px 18px;border-radius:20px;font-size:.85rem;font-weight:700;margin-top:12px}
|
|
43
|
+
.status-dead{background:#2a1f1f;color:var(--red);border:1px solid #5a2020}
|
|
44
|
+
.status-sub{background:#2a2015;color:var(--amber);border:1px solid #5a4020}
|
|
45
|
+
.status-self{background:#1a3a2a;color:var(--green);border:1px solid #2a6a3a}
|
|
46
|
+
.status-exp{background:#1a2a4a;color:var(--accent);border:1px solid #2a4a8a;animation:glow 2s infinite}
|
|
47
|
+
@keyframes glow{0%,100%{box-shadow:0 0 8px #58a6ff40}50%{box-shadow:0 0 20px #58a6ff80}}
|
|
48
|
+
|
|
49
|
+
/* slider section */
|
|
50
|
+
.slider-grid{display:grid;grid-template-columns:1fr 1fr;gap:24px}
|
|
51
|
+
@media(max-width:640px){.slider-grid{grid-template-columns:1fr}}
|
|
52
|
+
.slider-group{display:flex;flex-direction:column;gap:8px}
|
|
53
|
+
.slider-group label{font-size:.82rem;color:var(--muted);font-weight:600;text-transform:uppercase;letter-spacing:.05em;display:flex;justify-content:space-between}
|
|
54
|
+
.slider-group label span{color:var(--accent);font-size:.95rem}
|
|
55
|
+
input[type=range]{width:100%;accent-color:var(--accent);cursor:pointer;height:4px}
|
|
56
|
+
|
|
57
|
+
/* growth chart */
|
|
58
|
+
.chart-wrap{position:relative;background:#0d1117;border:1px solid var(--border);border-radius:8px;overflow:hidden;height:220px}
|
|
59
|
+
canvas#growthChart{width:100%;height:100%}
|
|
60
|
+
.chart-legend{display:flex;gap:20px;margin-top:10px;flex-wrap:wrap;font-size:.8rem}
|
|
61
|
+
.legend-item{display:flex;align-items:center;gap:6px}
|
|
62
|
+
.legend-dot{width:10px;height:10px;border-radius:50%}
|
|
63
|
+
|
|
64
|
+
/* layer cards */
|
|
65
|
+
.layers{display:grid;grid-template-columns:1fr;gap:12px}
|
|
66
|
+
.layer-card{background:#0d1117;border:1px solid var(--border);border-radius:8px;padding:18px;display:flex;gap:16px;align-items:flex-start}
|
|
67
|
+
.layer-num{background:var(--panel);border:1px solid var(--border);border-radius:6px;padding:6px 10px;font-weight:700;color:var(--accent);font-size:.88rem;flex-shrink:0;min-width:64px;text-align:center}
|
|
68
|
+
.layer-card h3{font-size:.95rem;font-weight:700;margin-bottom:4px}
|
|
69
|
+
.layer-card p{color:var(--muted);font-size:.85rem;line-height:1.5}
|
|
70
|
+
.layer-card .contrib{display:inline-block;background:#1c2128;border:1px solid var(--border);border-radius:12px;padding:2px 9px;font-size:.75rem;color:var(--accent);margin-top:6px}
|
|
71
|
+
|
|
72
|
+
/* math block */
|
|
73
|
+
.math-block{background:#0d1117;border:1px solid var(--border);border-radius:8px;padding:20px 24px;font-family:'Cascadia Code','Fira Code',monospace;font-size:.9rem;line-height:2;overflow-x:auto}
|
|
74
|
+
.math-block .eq{color:var(--text)}.math-block .var{color:var(--accent)}.math-block .op{color:var(--purple)}.math-block .cmt{color:var(--muted)}
|
|
75
|
+
|
|
76
|
+
/* critical mass progress */
|
|
77
|
+
.progress-bar-outer{background:#1c2128;border-radius:6px;height:18px;overflow:hidden;margin:8px 0}
|
|
78
|
+
.progress-bar-inner{height:100%;border-radius:6px;background:linear-gradient(90deg,var(--accent),var(--green));transition:width .8s ease;position:relative}
|
|
79
|
+
.progress-bar-inner::after{content:attr(data-pct);position:absolute;right:6px;top:50%;transform:translateY(-50%);font-size:.7rem;font-weight:700;color:#000}
|
|
80
|
+
|
|
81
|
+
/* source breakdown table */
|
|
82
|
+
.src-table{width:100%;border-collapse:collapse;font-size:.88rem}
|
|
83
|
+
.src-table th{text-align:left;padding:8px 12px;border-bottom:2px solid var(--border);color:var(--muted);font-size:.75rem;text-transform:uppercase;letter-spacing:.05em}
|
|
84
|
+
.src-table td{padding:8px 12px;border-bottom:1px solid var(--border)}
|
|
85
|
+
.src-table tr:last-child td{border:none}
|
|
86
|
+
.src-badge{display:inline-block;padding:2px 8px;border-radius:10px;font-size:.75rem;font-weight:600}
|
|
87
|
+
.src-gossip{background:#1a2a4a;color:var(--accent)}
|
|
88
|
+
.src-spider{background:#1a3a2a;color:var(--green)}
|
|
89
|
+
.src-manual{background:#2a2015;color:var(--amber)}
|
|
90
|
+
.src-unknown{background:#1c2128;color:var(--muted)}
|
|
91
|
+
</style>
|
|
92
|
+
</head>
|
|
93
|
+
<body>
|
|
94
|
+
|
|
95
|
+
<header>
|
|
96
|
+
<div class="logo">Web Agent <span>Bridge</span></div>
|
|
97
|
+
<div class="badge">v3.20.0</div>
|
|
98
|
+
<div class="badge" style="background:#1a2a4a;color:var(--accent);border-color:#264a8e">Viral Mathematics</div>
|
|
99
|
+
<nav>
|
|
100
|
+
<a href="/">Home</a>
|
|
101
|
+
<a href="/wab-registry">Registry</a>
|
|
102
|
+
<a href="/wab-dataset">Dataset</a>
|
|
103
|
+
<a href="/observatory">Observatory</a>
|
|
104
|
+
</nav>
|
|
105
|
+
</header>
|
|
106
|
+
|
|
107
|
+
<main>
|
|
108
|
+
<h1>WAB Viral Coefficient</h1>
|
|
109
|
+
<p class="subtitle">
|
|
110
|
+
The WAB Spider Network spreads like a virus — but a beneficial one.
|
|
111
|
+
Each WAB-enabled site discovers and recruits others through Beacons, Gossip, and DNA headers.
|
|
112
|
+
Below is the live mathematical model of that propagation.
|
|
113
|
+
When k > 1 the network grows by itself. When k > 2 it grows exponentially.
|
|
114
|
+
</p>
|
|
115
|
+
|
|
116
|
+
<!-- R0 Gauge -->
|
|
117
|
+
<div class="r0-gauge">
|
|
118
|
+
<div class="r0-value" id="r0Val">—</div>
|
|
119
|
+
<div class="r0-label">Viral Coefficient (k-factor)</div>
|
|
120
|
+
<div class="r0-status status-sub" id="r0Status">Calculating…</div>
|
|
121
|
+
</div>
|
|
122
|
+
|
|
123
|
+
<!-- Live KPIs -->
|
|
124
|
+
<div class="kpi-row">
|
|
125
|
+
<div class="kpi blue"><div class="val" id="kpiTotal">—</div><div class="lbl">Total WAB Sites</div></div>
|
|
126
|
+
<div class="kpi green"><div class="val" id="kpiGossip">—</div><div class="lbl">Gossip-Discovered</div></div>
|
|
127
|
+
<div class="kpi amber"><div class="val" id="kpiSpider">—</div><div class="lbl">Spider-Discovered</div></div>
|
|
128
|
+
<div class="kpi amber"><div class="val" id="kpiManual">—</div><div class="lbl">Manually Seeded</div></div>
|
|
129
|
+
</div>
|
|
130
|
+
|
|
131
|
+
<!-- Math -->
|
|
132
|
+
<section>
|
|
133
|
+
<h2>The Mathematics</h2>
|
|
134
|
+
<div class="panel">
|
|
135
|
+
<div class="math-block">
|
|
136
|
+
<span class="cmt">// WAB Viral Coefficient (k-factor)</span>
|
|
137
|
+
<span class="var">k</span> <span class="op">=</span> <span class="var">viral_discovered</span> <span class="op">/</span> <span class="var">manually_seeded</span>
|
|
138
|
+
|
|
139
|
+
<span class="cmt">// viral_discovered = gossip-sourced + spider-sourced registrations</span>
|
|
140
|
+
<span class="cmt">// manually_seeded = human-reported domains (seed nodes)</span>
|
|
141
|
+
|
|
142
|
+
<span class="cmt">// Growth equation after n iterations:</span>
|
|
143
|
+
<span class="var">sites(n)</span> <span class="op">=</span> <span class="var">seed</span> <span class="op">×</span> <span class="var">k</span><span class="op">^</span><span class="var">n</span>
|
|
144
|
+
|
|
145
|
+
<span class="cmt">// Condition for exponential growth:</span>
|
|
146
|
+
<span class="var">k</span> <span class="op">></span> 1 <span class="op">→</span> self-sustaining
|
|
147
|
+
<span class="var">k</span> <span class="op">></span> 2 <span class="op">→</span> exponential (doubles each iteration)
|
|
148
|
+
<span class="var">k</span> <span class="op"><</span> 1 <span class="op">→</span> decaying (needs more manual seeding)
|
|
149
|
+
|
|
150
|
+
<span class="cmt">// Critical mass (point of no return):</span>
|
|
151
|
+
<span class="var">critical_mass</span> <span class="op">≈</span> 1000 <span class="cmt">// diverse WAB sites across industries</span>
|
|
152
|
+
<span class="cmt">// At critical_mass, network effects make non-WAB sites invisible to agents</span>
|
|
153
|
+
</div>
|
|
154
|
+
</div>
|
|
155
|
+
</section>
|
|
156
|
+
|
|
157
|
+
<!-- Interactive simulator -->
|
|
158
|
+
<section>
|
|
159
|
+
<h2>Interactive Growth Simulator</h2>
|
|
160
|
+
<div class="panel">
|
|
161
|
+
<div class="slider-grid" style="margin-bottom:24px">
|
|
162
|
+
<div class="slider-group">
|
|
163
|
+
<label>Seed Sites <span id="slSeed">1</span></label>
|
|
164
|
+
<input type="range" id="sliderSeed" min="1" max="50" value="1" oninput="simUpdate()">
|
|
165
|
+
</div>
|
|
166
|
+
<div class="slider-group">
|
|
167
|
+
<label>k-factor <span id="slK">1.5</span></label>
|
|
168
|
+
<input type="range" id="sliderK" min="0.5" max="4.0" step="0.1" value="1.5" oninput="simUpdate()">
|
|
169
|
+
</div>
|
|
170
|
+
<div class="slider-group">
|
|
171
|
+
<label>Gossip reach (peers/node) <span id="slPeers">5</span></label>
|
|
172
|
+
<input type="range" id="sliderPeers" min="1" max="20" value="5" oninput="simUpdate()">
|
|
173
|
+
</div>
|
|
174
|
+
<div class="slider-group">
|
|
175
|
+
<label>Adoption probability <span id="slAdopt">0.30</span></label>
|
|
176
|
+
<input type="range" id="sliderAdopt" min="0.05" max="1.0" step="0.05" value="0.30" oninput="simUpdate()">
|
|
177
|
+
</div>
|
|
178
|
+
</div>
|
|
179
|
+
<div class="chart-wrap">
|
|
180
|
+
<canvas id="growthChart"></canvas>
|
|
181
|
+
</div>
|
|
182
|
+
<div class="chart-legend" style="margin-top:12px">
|
|
183
|
+
<div class="legend-item"><div class="legend-dot" style="background:var(--accent)"></div>Simulated growth</div>
|
|
184
|
+
<div class="legend-item"><div class="legend-dot" style="background:var(--green)"></div>Critical mass (1000)</div>
|
|
185
|
+
<div class="legend-item" id="critMassLegend" style="color:var(--muted);font-size:.78rem"></div>
|
|
186
|
+
</div>
|
|
187
|
+
<div style="margin-top:12px;color:var(--muted);font-size:.82rem" id="simSummary"></div>
|
|
188
|
+
</div>
|
|
189
|
+
</section>
|
|
190
|
+
|
|
191
|
+
<!-- Critical mass progress -->
|
|
192
|
+
<section>
|
|
193
|
+
<h2>Critical Mass Progress</h2>
|
|
194
|
+
<div class="panel">
|
|
195
|
+
<div style="display:flex;justify-content:space-between;font-size:.85rem;margin-bottom:4px">
|
|
196
|
+
<span>WAB Network Size</span>
|
|
197
|
+
<span id="cmLabel" style="color:var(--muted)">0 / 1000</span>
|
|
198
|
+
</div>
|
|
199
|
+
<div class="progress-bar-outer">
|
|
200
|
+
<div class="progress-bar-inner" id="cmBar" data-pct="0%" style="width:0%"></div>
|
|
201
|
+
</div>
|
|
202
|
+
<p style="color:var(--muted);font-size:.82rem;line-height:1.6;margin-top:12px">
|
|
203
|
+
At <strong>1,000 sites</strong> across diverse industries, the WAB network effect
|
|
204
|
+
becomes irreversible: AI agents that skip WAB miss structured data from the majority
|
|
205
|
+
of the web, producing inferior results. Non-WAB sites become the fallback, not the default.
|
|
206
|
+
</p>
|
|
207
|
+
</div>
|
|
208
|
+
</section>
|
|
209
|
+
|
|
210
|
+
<!-- Source breakdown -->
|
|
211
|
+
<section>
|
|
212
|
+
<h2>Network Source Breakdown</h2>
|
|
213
|
+
<div class="panel" style="overflow-x:auto">
|
|
214
|
+
<table class="src-table">
|
|
215
|
+
<thead>
|
|
216
|
+
<tr><th>Discovery Source</th><th>Count</th><th>Share</th><th>Description</th></tr>
|
|
217
|
+
</thead>
|
|
218
|
+
<tbody id="srcBody">
|
|
219
|
+
<tr><td colspan="4" style="color:var(--muted);text-align:center;padding:20px">Loading…</td></tr>
|
|
220
|
+
</tbody>
|
|
221
|
+
</table>
|
|
222
|
+
</div>
|
|
223
|
+
</section>
|
|
224
|
+
|
|
225
|
+
<!-- Five propagation layers -->
|
|
226
|
+
<section>
|
|
227
|
+
<h2>Five Self-Propagation Layers</h2>
|
|
228
|
+
<div class="layers">
|
|
229
|
+
<div class="layer-card">
|
|
230
|
+
<div class="layer-num">Layer 0</div>
|
|
231
|
+
<div>
|
|
232
|
+
<h3>Emergent Preference</h3>
|
|
233
|
+
<p>Agents naturally choose WAB sites over DOM scraping because structured APIs are faster and more reliable. No instruction needed — it's the rational choice.</p>
|
|
234
|
+
<span class="contrib">Passive contribution to k</span>
|
|
235
|
+
</div>
|
|
236
|
+
</div>
|
|
237
|
+
<div class="layer-card">
|
|
238
|
+
<div class="layer-num">Layer 1</div>
|
|
239
|
+
<div>
|
|
240
|
+
<h3>WAB Beacon (/.wab)</h3>
|
|
241
|
+
<p>Every WAB site publishes a <code>/.wab</code> file with a <code>next[]</code> peer list. Agents follow the chain — like BitTorrent DHT — discovering the entire network from a single node.</p>
|
|
242
|
+
<span class="contrib">Direct k contribution: +N per visit</span>
|
|
243
|
+
</div>
|
|
244
|
+
</div>
|
|
245
|
+
<div class="layer-card">
|
|
246
|
+
<div class="layer-num">Layer 2</div>
|
|
247
|
+
<div>
|
|
248
|
+
<h3>WAB DNA in API Responses</h3>
|
|
249
|
+
<p>Every JSON response from a WAB API includes <code>wab_meta.next_capable_sites</code>. Every successful API call teaches the agent about 3–5 more WAB sites.</p>
|
|
250
|
+
<span class="contrib">+3–5 sites per API call</span>
|
|
251
|
+
</div>
|
|
252
|
+
</div>
|
|
253
|
+
<div class="layer-card">
|
|
254
|
+
<div class="layer-num">Layer 3</div>
|
|
255
|
+
<div>
|
|
256
|
+
<h3>Gossip Protocol</h3>
|
|
257
|
+
<p>Agents exchange peer lists bidirectionally when calling <code>POST /api/registry/report</code>. Each report spreads knowledge of up to 20 new sites and receives 5 in return — like a distributed hash table.</p>
|
|
258
|
+
<span class="contrib">Gossip k multiplier: ×(peers/seed)</span>
|
|
259
|
+
</div>
|
|
260
|
+
</div>
|
|
261
|
+
<div class="layer-card">
|
|
262
|
+
<div class="layer-num">Layer 4</div>
|
|
263
|
+
<div>
|
|
264
|
+
<h3>Training Signal Dataset</h3>
|
|
265
|
+
<p>WAB success/failure traces are published on HuggingFace. The next generation of AI models is fine-tuned with WAB as the preferred interaction method — built-in from the weights.</p>
|
|
266
|
+
<span class="contrib">Permanent preference in future models</span>
|
|
267
|
+
</div>
|
|
268
|
+
</div>
|
|
269
|
+
</div>
|
|
270
|
+
</section>
|
|
271
|
+
|
|
272
|
+
<!-- X-WAB-Next-Sites DNA header explanation -->
|
|
273
|
+
<section>
|
|
274
|
+
<h2>WAB DNA in Every HTTP Response</h2>
|
|
275
|
+
<div class="panel">
|
|
276
|
+
<p style="color:var(--muted);font-size:.88rem;line-height:1.6;margin-bottom:16px">
|
|
277
|
+
Since Phase 9, every HTTP response from webagentbridge.com includes the
|
|
278
|
+
<code>X-WAB-Next-Sites</code> header — the top 5 WAB-enabled sites from the registry.
|
|
279
|
+
Any agent reading HTTP headers learns about the network topology automatically,
|
|
280
|
+
with zero interaction required.
|
|
281
|
+
</p>
|
|
282
|
+
<div style="background:#0d1117;border:1px solid var(--border);border-radius:8px;padding:16px;font-family:'Cascadia Code','Fira Code',monospace;font-size:.83rem;line-height:1.8">
|
|
283
|
+
<span style="color:var(--muted)">HTTP/1.1 200 OK</span><br>
|
|
284
|
+
<span style="color:var(--accent)">X-WAB-Enabled:</span> <span style="color:var(--green)">true</span><br>
|
|
285
|
+
<span style="color:var(--accent)">X-WAB-Trust-Ring:</span> <span style="color:var(--green)">4</span><br>
|
|
286
|
+
<span style="color:var(--accent)">X-WAB-Score:</span> <span style="color:var(--green)">94</span><br>
|
|
287
|
+
<span style="color:var(--accent)">X-WAB-Next-Sites:</span> <span style="color:var(--amber)" id="nextSitesDisplay">takeyourappointment.com, …</span><br>
|
|
288
|
+
<span style="color:var(--accent)">X-WAB-Registry:</span> <span style="color:var(--muted)">/api/registry/discover</span><br>
|
|
289
|
+
<span style="color:var(--muted)">Link: </.wab>; rel="wab-beacon"</span>
|
|
290
|
+
</div>
|
|
291
|
+
<p style="color:var(--muted);font-size:.82rem;margin-top:12px">
|
|
292
|
+
Every page load — from every browser, every bot, every AI agent — carries this
|
|
293
|
+
DNA. The network topology propagates passively without any active agent participation.
|
|
294
|
+
</p>
|
|
295
|
+
</div>
|
|
296
|
+
</section>
|
|
297
|
+
|
|
298
|
+
</main>
|
|
299
|
+
|
|
300
|
+
<script>
|
|
301
|
+
// ── Live viral stats ─────────────────────────────────────────────────────────
|
|
302
|
+
async function loadViral() {
|
|
303
|
+
try {
|
|
304
|
+
const r = await fetch('/api/traces/viral');
|
|
305
|
+
const d = await r.json();
|
|
306
|
+
|
|
307
|
+
const k = d.k_factor;
|
|
308
|
+
const r0El = document.getElementById('r0Val');
|
|
309
|
+
const statEl = document.getElementById('r0Status');
|
|
310
|
+
r0El.textContent = k != null ? k.toFixed(2) : '—';
|
|
311
|
+
|
|
312
|
+
if (k == null) {
|
|
313
|
+
r0El.style.color = 'var(--muted)';
|
|
314
|
+
statEl.className = 'r0-status status-sub'; statEl.textContent = 'Insufficient data';
|
|
315
|
+
} else if (k >= 2) {
|
|
316
|
+
r0El.style.color = 'var(--accent)';
|
|
317
|
+
statEl.className = 'r0-status status-exp'; statEl.textContent = '🚀 Exponential Growth';
|
|
318
|
+
} else if (k >= 1) {
|
|
319
|
+
r0El.style.color = 'var(--green)';
|
|
320
|
+
statEl.className = 'r0-status status-self'; statEl.textContent = '✓ Self-Sustaining';
|
|
321
|
+
} else if (k > 0) {
|
|
322
|
+
r0El.style.color = 'var(--amber)';
|
|
323
|
+
statEl.className = 'r0-status status-sub'; statEl.textContent = `Sub-threshold — needs ${(1/k).toFixed(1)}× more viral reports`;
|
|
324
|
+
} else {
|
|
325
|
+
r0El.style.color = 'var(--red)';
|
|
326
|
+
statEl.className = 'r0-status status-dead'; statEl.textContent = 'No viral spread yet';
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
document.getElementById('kpiTotal').textContent = (d.total_sites || 0).toLocaleString();
|
|
330
|
+
document.getElementById('kpiGossip').textContent = (d.gossip_sourced || 0).toLocaleString();
|
|
331
|
+
document.getElementById('kpiSpider').textContent = (d.spider_sourced || 0).toLocaleString();
|
|
332
|
+
document.getElementById('kpiManual').textContent = (d.manually_seeded || 0).toLocaleString();
|
|
333
|
+
|
|
334
|
+
const pct = Math.min(100, ((d.total_sites || 0) / 1000) * 100).toFixed(1);
|
|
335
|
+
document.getElementById('cmBar').style.width = pct + '%';
|
|
336
|
+
document.getElementById('cmBar').dataset.pct = pct + '%';
|
|
337
|
+
document.getElementById('cmLabel').textContent = `${d.total_sites || 0} / 1000`;
|
|
338
|
+
|
|
339
|
+
// Source breakdown table
|
|
340
|
+
const src = d.by_source || {};
|
|
341
|
+
const total = d.total_sites || 0;
|
|
342
|
+
const rows = [
|
|
343
|
+
{ key: 'gossip', label: 'Gossip Protocol', cls: 'src-gossip' },
|
|
344
|
+
{ key: 'agent_browsing', label: 'Spider Protocol', cls: 'src-spider' },
|
|
345
|
+
{ key: 'spider', label: 'Spider (alt)', cls: 'src-spider' },
|
|
346
|
+
{ key: 'manual_registry_form', label: 'Manual (form)', cls: 'src-manual' },
|
|
347
|
+
{ key: 'manual', label: 'Manual (seed)', cls: 'src-manual' },
|
|
348
|
+
{ key: 'test', label: 'Test seed', cls: 'src-manual' },
|
|
349
|
+
{ key: 'unknown', label: 'Unknown', cls: 'src-unknown' },
|
|
350
|
+
].filter(r => src[r.key] > 0);
|
|
351
|
+
|
|
352
|
+
if (rows.length === 0) {
|
|
353
|
+
document.getElementById('srcBody').innerHTML =
|
|
354
|
+
'<tr><td colspan="4" style="color:var(--muted);text-align:center;padding:16px">No sites registered yet.</td></tr>';
|
|
355
|
+
} else {
|
|
356
|
+
document.getElementById('srcBody').innerHTML = rows.map(r => {
|
|
357
|
+
const cnt = src[r.key] || 0;
|
|
358
|
+
const share= total > 0 ? (cnt / total * 100).toFixed(1) + '%' : '—';
|
|
359
|
+
return `<tr>
|
|
360
|
+
<td><span class="src-badge ${r.cls}">${r.label}</span></td>
|
|
361
|
+
<td>${cnt}</td>
|
|
362
|
+
<td>${share}</td>
|
|
363
|
+
<td style="color:var(--muted);font-size:.82rem">${describeSource(r.key)}</td>
|
|
364
|
+
</tr>`;
|
|
365
|
+
}).join('');
|
|
366
|
+
}
|
|
367
|
+
} catch(e) { console.error(e); }
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
function describeSource(k) {
|
|
371
|
+
const m = {
|
|
372
|
+
gossip: 'Agents shared this domain via gossip_peers in a POST /report call.',
|
|
373
|
+
agent_browsing: 'An AI agent discovered this site while browsing and reported it.',
|
|
374
|
+
spider: 'WAB Spider Protocol (automatic agent report).',
|
|
375
|
+
manual_registry_form: 'Submitted via the manual registry form on wab-registry.html.',
|
|
376
|
+
manual: 'Manually seeded (human action).',
|
|
377
|
+
test: 'Test entry seeded during development.',
|
|
378
|
+
unknown: 'Discovery source not recorded.',
|
|
379
|
+
};
|
|
380
|
+
return m[k] || '—';
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// ── Live DNA header display ────────────────────────────────────────────────
|
|
384
|
+
async function loadNextSites() {
|
|
385
|
+
try {
|
|
386
|
+
const r = await fetch('/api/registry/gossip?limit=5');
|
|
387
|
+
const d = await r.json();
|
|
388
|
+
if (d.peers && d.peers.length > 0) {
|
|
389
|
+
document.getElementById('nextSitesDisplay').textContent =
|
|
390
|
+
d.peers.map(p => p.domain).join(', ');
|
|
391
|
+
}
|
|
392
|
+
} catch {}
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
// ── Growth Simulator ─────────────────────────────────────────────────────────
|
|
396
|
+
const CRIT_MASS = 1000;
|
|
397
|
+
let simChart = null;
|
|
398
|
+
|
|
399
|
+
function simUpdate() {
|
|
400
|
+
const seed = parseInt(document.getElementById('sliderSeed').value, 10);
|
|
401
|
+
const k = parseFloat(document.getElementById('sliderK').value);
|
|
402
|
+
const peers = parseInt(document.getElementById('sliderPeers').value, 10);
|
|
403
|
+
const adopt = parseFloat(document.getElementById('sliderAdopt').value);
|
|
404
|
+
|
|
405
|
+
document.getElementById('slSeed').textContent = seed;
|
|
406
|
+
document.getElementById('slK').textContent = k.toFixed(1);
|
|
407
|
+
document.getElementById('slPeers').textContent = peers;
|
|
408
|
+
document.getElementById('slAdopt').textContent = adopt.toFixed(2);
|
|
409
|
+
|
|
410
|
+
// Effective k from sliders: k = peers * adopt
|
|
411
|
+
const kEff = peers * adopt;
|
|
412
|
+
|
|
413
|
+
// Generate growth series (20 iterations)
|
|
414
|
+
const iters = 20;
|
|
415
|
+
const labels = Array.from({length: iters + 1}, (_, i) => `Step ${i}`);
|
|
416
|
+
const data = [seed];
|
|
417
|
+
for (let i = 0; i < iters; i++) {
|
|
418
|
+
data.push(Math.min(1e7, data[data.length - 1] * (kEff > 0 ? kEff : k)));
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
// Find critical mass crossing
|
|
422
|
+
let critStep = null;
|
|
423
|
+
for (let i = 0; i < data.length; i++) {
|
|
424
|
+
if (data[i] >= CRIT_MASS) { critStep = i; break; }
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
drawChart(labels, data, critStep);
|
|
428
|
+
|
|
429
|
+
document.getElementById('simSummary').textContent =
|
|
430
|
+
critStep != null
|
|
431
|
+
? `Critical mass (${CRIT_MASS} sites) reached at step ${critStep}. Effective k = ${kEff.toFixed(2)}.`
|
|
432
|
+
: `Critical mass not reached in ${iters} steps with effective k = ${kEff.toFixed(2)}. Try increasing peers or adoption probability.`;
|
|
433
|
+
|
|
434
|
+
document.getElementById('critMassLegend').textContent =
|
|
435
|
+
critStep != null ? `Critical mass at step ${critStep}` : 'Critical mass not reached';
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
function drawChart(labels, data, critStep) {
|
|
439
|
+
const canvas = document.getElementById('growthChart');
|
|
440
|
+
const ctx = canvas.getContext('2d');
|
|
441
|
+
const W = canvas.parentElement.clientWidth || 800;
|
|
442
|
+
const H = canvas.parentElement.clientHeight || 220;
|
|
443
|
+
canvas.width = W;
|
|
444
|
+
canvas.height = H;
|
|
445
|
+
ctx.clearRect(0, 0, W, H);
|
|
446
|
+
|
|
447
|
+
const pad = { top: 20, right: 20, bottom: 30, left: 60 };
|
|
448
|
+
const pw = W - pad.left - pad.right;
|
|
449
|
+
const ph = H - pad.top - pad.bottom;
|
|
450
|
+
|
|
451
|
+
const maxVal = Math.max(...data, CRIT_MASS);
|
|
452
|
+
const useLog = maxVal > 5000;
|
|
453
|
+
|
|
454
|
+
function scaleY(v) {
|
|
455
|
+
if (useLog) {
|
|
456
|
+
const logMax = Math.log10(maxVal + 1);
|
|
457
|
+
return ph - (Math.log10(v + 1) / logMax) * ph;
|
|
458
|
+
}
|
|
459
|
+
return ph - (v / maxVal) * ph;
|
|
460
|
+
}
|
|
461
|
+
function scaleX(i) { return (i / (data.length - 1)) * pw; }
|
|
462
|
+
|
|
463
|
+
// Grid lines
|
|
464
|
+
ctx.strokeStyle = '#30363d'; ctx.lineWidth = 1;
|
|
465
|
+
for (let g = 0; g <= 4; g++) {
|
|
466
|
+
const y = pad.top + (g / 4) * ph;
|
|
467
|
+
ctx.beginPath(); ctx.moveTo(pad.left, y); ctx.lineTo(pad.left + pw, y); ctx.stroke();
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
// Critical mass line
|
|
471
|
+
const cmY = pad.top + scaleY(CRIT_MASS);
|
|
472
|
+
ctx.strokeStyle = '#3fb950'; ctx.lineWidth = 1.5; ctx.setLineDash([5, 4]);
|
|
473
|
+
ctx.beginPath(); ctx.moveTo(pad.left, cmY); ctx.lineTo(pad.left + pw, cmY); ctx.stroke();
|
|
474
|
+
ctx.setLineDash([]);
|
|
475
|
+
ctx.fillStyle = '#3fb95099'; ctx.font = '10px sans-serif'; ctx.fillText('Critical mass', pad.left + 4, cmY - 4);
|
|
476
|
+
|
|
477
|
+
// Step-crossed marker
|
|
478
|
+
if (critStep != null) {
|
|
479
|
+
const cx = pad.left + scaleX(critStep);
|
|
480
|
+
ctx.strokeStyle = '#3fb95066'; ctx.lineWidth = 1.5; ctx.setLineDash([4, 4]);
|
|
481
|
+
ctx.beginPath(); ctx.moveTo(cx, pad.top); ctx.lineTo(cx, pad.top + ph); ctx.stroke();
|
|
482
|
+
ctx.setLineDash([]);
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
// Growth curve
|
|
486
|
+
ctx.strokeStyle = '#58a6ff'; ctx.lineWidth = 2.5;
|
|
487
|
+
ctx.beginPath();
|
|
488
|
+
for (let i = 0; i < data.length; i++) {
|
|
489
|
+
const x = pad.left + scaleX(i);
|
|
490
|
+
const y = pad.top + scaleY(data[i]);
|
|
491
|
+
i === 0 ? ctx.moveTo(x, y) : ctx.lineTo(x, y);
|
|
492
|
+
}
|
|
493
|
+
ctx.stroke();
|
|
494
|
+
|
|
495
|
+
// Fill under curve
|
|
496
|
+
ctx.beginPath();
|
|
497
|
+
for (let i = 0; i < data.length; i++) {
|
|
498
|
+
const x = pad.left + scaleX(i);
|
|
499
|
+
const y = pad.top + scaleY(data[i]);
|
|
500
|
+
i === 0 ? ctx.moveTo(x, y) : ctx.lineTo(x, y);
|
|
501
|
+
}
|
|
502
|
+
ctx.lineTo(pad.left + pw, pad.top + ph);
|
|
503
|
+
ctx.lineTo(pad.left, pad.top + ph);
|
|
504
|
+
ctx.closePath();
|
|
505
|
+
ctx.fillStyle = '#58a6ff14'; ctx.fill();
|
|
506
|
+
|
|
507
|
+
// Axis labels
|
|
508
|
+
ctx.fillStyle = '#8b949e'; ctx.font = '10px sans-serif';
|
|
509
|
+
// Y axis
|
|
510
|
+
const yTicks = 5;
|
|
511
|
+
for (let g = 0; g <= yTicks; g++) {
|
|
512
|
+
const v = useLog
|
|
513
|
+
? Math.round(Math.pow(10, (g / yTicks) * Math.log10(maxVal + 1)) - 1)
|
|
514
|
+
: Math.round((g / yTicks) * maxVal);
|
|
515
|
+
const y = pad.top + ph - (g / yTicks) * ph;
|
|
516
|
+
ctx.fillText(v >= 1000 ? (v/1000).toFixed(0)+'k' : v, 2, y + 4);
|
|
517
|
+
}
|
|
518
|
+
// X axis
|
|
519
|
+
const step = Math.max(1, Math.round(data.length / 6));
|
|
520
|
+
for (let i = 0; i < data.length; i += step) {
|
|
521
|
+
const x = pad.left + scaleX(i);
|
|
522
|
+
ctx.fillText(i, x - 4, H - 6);
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
loadViral();
|
|
527
|
+
loadNextSites();
|
|
528
|
+
simUpdate();
|
|
529
|
+
setInterval(loadViral, 30000);
|
|
530
|
+
window.addEventListener('resize', simUpdate);
|
|
531
|
+
</script>
|
|
532
|
+
</body>
|
|
533
|
+
</html>
|