Skip to content

Commit 3150f97

Browse files
committed
Add DV2.0 multi-branch live demo to DE_project section
Self-hosted asciinema playback at proof-pack/dv2_demo.html. Plays the 42-second cast captured against the live hq-demo Kubernetes cluster on 2026-05-23 — five branches, 39 satellites, BV MDM, anonymized cold tier. Adds a secondary pill in the DE_project section linking to the demo page; no other layout changes. The cast file (dv2_demo.cast, 4.8 KB) ships from the same origin as the page so playback works without asciinema.org and survives anonymous-TTL expiry on the hosted upload. Source for the cast is tracked in the AgentFlow repo at docs/dv2-multi-branch/demo.cast.
1 parent 6486781 commit 3150f97

3 files changed

Lines changed: 295 additions & 0 deletions

File tree

‎dv2_demo.cast‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
{"version": 2, "width": 130, "height": 35, "timestamp": 1779531590, "env": {"SHELL": "/bin/bash", "TERM": "xterm-256color"}, "title": "DV2.0 multi-branch live demo"}
2+
[0.01269, "o", "\r\n\u001b[1;33m# === Beat 1 — Cluster topology (00:25) ===\u001b[0m\r\n"]
3+
[1.520249, "o", "\u001b[1;36m$\u001b[0m kubectl get nodes --show-labels | head -5\r\n"]
4+
[2.411272, "o", "NAME STATUS ROLES AGE VERSION LABELS\r\nhq-demo-control-plane Ready control-plane 6h18m v1.35.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,branch=msk,kubernetes.io/arch=amd64,kubernetes.io/hostname=hq-demo-control-plane,kubernetes.io/os=linux,node-role.kubernetes.io/control-plane=,node.kubernetes.io/exclude-from-external-load-balancers=,nodepool=hq-control\r\nhq-demo-worker Ready <none> 6h18m v1.35.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,branch=msk,kubernetes.io/arch=amd64,kubernetes.io/hostname=hq-demo-worker,kubernetes.io/os=linux,nodepool=hq-data-tier-a,workload=postgres\r\nhq-demo-worker2 Ready <none> 6h18m v1.35.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,branch=msk,kubernetes.io/arch=amd64,kubernetes.io/hostname=hq-demo-worker2,kubernetes.io/os=linux,nodepool=hq-data-tier-b,workload=clickhouse\r\n"]
5+
[4.921556, "o", "\r\n\u001b[1;33m# === Beat 2 — DV2.0 model surface (00:45) ===\u001b[0m\r\n"]
6+
[6.434524, "o", "\u001b[1;36m$\u001b[0m kubectl exec -n dv2 clickhouse-0 -- clickhouse-client --user default --password demo --query \"SELECT splitByString('_', name)[1] AS kind, count() FROM system.tables WHERE database='rv' GROUP BY kind ORDER BY kind\"\r\n"]
7+
[7.428901, "o", "bv\t6\r\nhub\t8\r\nlnk\t8\r\nsat\t39\r\n"]
8+
[9.95663, "o", "\r\n\u001b[1;33m# === Beat 3 — Multi-branch distribution (01:05) ===\u001b[0m\r\n"]
9+
[11.465034, "o", "\u001b[1;36m$\u001b[0m kubectl exec -n dv2 clickhouse-0 -- clickhouse-client --user default --password demo --query \"SELECT splitByString('__', record_source)[2] AS branch, count() AS orders, round(count()*100.0/(SELECT count() FROM rv.hub_order),1) AS pct FROM rv.hub_order GROUP BY branch ORDER BY pct DESC FORMAT PrettyCompact\"\r\n"]
10+
[12.475313, "o", " ┌─branch─┬─orders─┬──pct─┐\r\n1. │ msk │ 4200 │ 40.5 │\r\n2. │ spb │ 2500 │ 24.1 │\r\n3. │ ekb │ 1500 │ 14.5 │\r\n4. │ dxb │ 1160 │ 11.2 │\r\n5. │ ala │ 1000 │ 9.7 │\r\n └────────┴────────┴──────┘\r\n"]
11+
[14.995744, "o", "\r\n\u001b[1;33m# === Beat 4 — Business Vault MDM (01:25) ===\u001b[0m\r\n"]
12+
[16.50705, "o", "\u001b[1;36m$\u001b[0m kubectl exec -n dv2 clickhouse-0 -- clickhouse-client --user default --password demo --multiline --query \"SELECT 'msk' AS branch, count() AS rows, countIf(first_name != '') AS with_pii, countIf(loyalty_segment != '') AS with_loyalty FROM rv.bv_customer_mdm__msk UNION ALL SELECT 'dxb', count(), countIf(first_name != ''), countIf(loyalty_segment IS NOT NULL AND loyalty_segment != '') FROM rv.bv_customer_mdm__dxb FORMAT PrettyCompact\"\r\n"]
13+
[17.550896, "o", " ┌─branch─┬─rows─┬─with_pii─┬─with_loyalty─┐\r\n1. │ dxb │ 200 │ 200 │ 0 │\r\n2. │ msk │ 800 │ 800 │ 640 │\r\n └────────┴──────┴──────────┴──────────────┘\r\n"]
14+
[20.072279, "o", "\r\n\u001b[1;33m# === Beat 5a — Cold offload (01:50) ===\u001b[0m\r\n"]
15+
[21.576438, "o", "\u001b[1;36m$\u001b[0m kubectl create job --from=cronjob/dv2-cold-offload-msk cold-demo-3455 -n dv2\r\n"]
16+
[22.483005, "o", "job.batch/cold-demo-3455 created\r\n"]
17+
[32.996093, "o", "\r\n\u001b[1;33m# === Beat 5b — MinIO parquet listing ===\u001b[0m\r\n"]
18+
[34.50554, "o", "\u001b[1;36m$\u001b[0m kubectl exec -n dv2 minio-0 -- mc ls -r local/cold-tier | tail -5\r\n"]
19+
[35.495859, "o", "[2026-05-23 09:44:37 UTC] 6.7KiB STANDARD branch=ala/year=2026/month=05/customers_anon.parquet\r\n[2026-05-23 09:44:32 UTC] 6.7KiB STANDARD branch=dxb/year=2026/month=05/customers_anon.parquet\r\n[2026-05-23 09:44:37 UTC] 8.6KiB STANDARD branch=ekb/year=2026/month=05/customers_anon.parquet\r\n[2026-05-23 10:20:13 UTC] 20KiB STANDARD branch=msk/year=2026/month=05/customers_anon.parquet\r\n[2026-05-23 09:44:32 UTC] 13KiB STANDARD branch=spb/year=2026/month=05/customers_anon.parquet\r\n"]
20+
[38.005981, "o", "\r\n\u001b[1;33m# === Closing (02:00) — Single bootstrap reproduces everything ===\u001b[0m\r\n"]
21+
[39.516429, "o", "\u001b[1;36m$\u001b[0m bash infrastructure/dv2/bootstrap.sh\r\n"]
22+
[41.521865, "o", "\r\n\u001b[1;33mDemo complete. See docs/dv2-multi-branch/demo_evidence.md for the full breakdown.\u001b[0m\r\n"]

‎dv2_demo.html‎

Lines changed: 272 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,272 @@
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>DV2.0 Multi-Branch Live Demo — AgentFlow</title>
7+
<meta name="description" content="42-second live recording of a Data Vault 2.0 multi-branch demo executing against a self-hosted Kubernetes cluster: 5 branches, 39 satellites, MDM, anonymized cold tier, end-to-end.">
8+
<link rel="canonical" href="https://brownjuly2003-code.github.io/proof-pack/dv2_demo.html">
9+
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Crect width='32' height='32' fill='%230a0a0a'/%3E%3Ctext x='16' y='22' font-family='Inter,sans-serif' font-size='18' font-weight='700' fill='%23fff' text-anchor='middle'%3EJ%3C/text%3E%3C/svg%3E">
10+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/asciinema-player@3/dist/bundle/asciinema-player.css" />
11+
<style>
12+
:root {
13+
--text: #0a0a0a;
14+
--muted: #525252;
15+
--soft: #737373;
16+
--bg: #fafafa;
17+
--frame: #e5e5e5;
18+
--accent: #2563eb;
19+
}
20+
*, *::before, *::after { box-sizing: border-box; }
21+
html, body {
22+
margin: 0;
23+
background: var(--bg);
24+
color: var(--text);
25+
font-family: -apple-system, BlinkMacSystemFont, "Inter", "Segoe UI", Helvetica, Arial, sans-serif;
26+
font-size: 16px;
27+
line-height: 1.55;
28+
-webkit-font-smoothing: antialiased;
29+
}
30+
main {
31+
max-width: 1040px;
32+
margin: 0 auto;
33+
padding: 56px 24px 64px;
34+
}
35+
.topnav {
36+
display: flex;
37+
gap: 18px;
38+
align-items: baseline;
39+
font-size: 13px;
40+
color: var(--muted);
41+
margin-bottom: 28px;
42+
}
43+
.topnav a {
44+
color: var(--muted);
45+
text-decoration: none;
46+
border-bottom: 1px solid transparent;
47+
}
48+
.topnav a:hover { color: var(--text); border-bottom-color: var(--text); }
49+
h1 {
50+
font-size: 30px;
51+
font-weight: 600;
52+
letter-spacing: -0.012em;
53+
margin: 0 0 10px;
54+
}
55+
.lede {
56+
color: var(--muted);
57+
font-size: 15.5px;
58+
margin: 0 0 32px;
59+
max-width: 760px;
60+
}
61+
.lede strong { color: var(--text); font-weight: 600; }
62+
.player {
63+
border: 1px solid var(--frame);
64+
border-radius: 6px;
65+
overflow: hidden;
66+
background: #000;
67+
box-shadow: 0 1px 2px rgba(0,0,0,.04), 0 8px 28px rgba(0,0,0,.06);
68+
}
69+
.meta {
70+
display: flex;
71+
gap: 18px;
72+
align-items: center;
73+
margin: 18px 0 36px;
74+
color: var(--soft);
75+
font-size: 13.5px;
76+
flex-wrap: wrap;
77+
}
78+
.meta .dot { color: var(--frame); }
79+
.meta a {
80+
color: var(--text);
81+
text-decoration: none;
82+
border-bottom: 1px solid var(--frame);
83+
}
84+
.meta a:hover { border-bottom-color: var(--text); }
85+
.meta .play-actions { margin-left: auto; display: flex; gap: 14px; }
86+
.meta .play-actions a {
87+
color: var(--accent);
88+
border-bottom: 1px solid transparent;
89+
}
90+
.meta .play-actions a:hover { border-bottom-color: var(--accent); }
91+
92+
section.beats { margin-top: 16px; }
93+
section.beats h2 {
94+
font-size: 13px;
95+
font-weight: 600;
96+
text-transform: uppercase;
97+
letter-spacing: .06em;
98+
color: var(--muted);
99+
margin: 0 0 14px;
100+
}
101+
.beats-grid {
102+
display: grid;
103+
grid-template-columns: 64px 1.1fr 1.3fr;
104+
gap: 10px 18px;
105+
font-size: 14px;
106+
}
107+
.beats-grid .t {
108+
color: var(--soft);
109+
font-family: "JetBrains Mono", "SF Mono", Menlo, Consolas, monospace;
110+
font-variant-numeric: tabular-nums;
111+
font-size: 12.5px;
112+
}
113+
.beats-grid .lab b { font-weight: 600; }
114+
.beats-grid code {
115+
font-family: "JetBrains Mono", "SF Mono", Menlo, Consolas, monospace;
116+
font-size: 12.5px;
117+
background: rgba(0,0,0,.04);
118+
padding: 1px 5px;
119+
border-radius: 3px;
120+
}
121+
122+
section.context {
123+
margin-top: 44px;
124+
padding-top: 24px;
125+
border-top: 1px solid var(--frame);
126+
}
127+
section.context h2 {
128+
font-size: 16px;
129+
font-weight: 600;
130+
margin: 0 0 12px;
131+
}
132+
section.context p {
133+
color: var(--muted);
134+
font-size: 14.5px;
135+
margin: 0 0 12px;
136+
max-width: 760px;
137+
}
138+
.stack {
139+
display: flex;
140+
flex-wrap: wrap;
141+
gap: 8px;
142+
margin: 16px 0 4px;
143+
}
144+
.stack span {
145+
font-size: 12px;
146+
font-family: "JetBrains Mono", "SF Mono", Menlo, monospace;
147+
color: var(--text);
148+
background: #fff;
149+
border: 1px solid var(--frame);
150+
padding: 4px 9px;
151+
border-radius: 3px;
152+
}
153+
footer {
154+
margin-top: 56px;
155+
padding-top: 22px;
156+
border-top: 1px solid var(--frame);
157+
font-size: 13px;
158+
color: var(--soft);
159+
}
160+
footer a { color: var(--muted); border-bottom: 1px solid var(--frame); text-decoration: none; }
161+
footer a:hover { color: var(--text); border-bottom-color: var(--text); }
162+
</style>
163+
</head>
164+
<body>
165+
<main>
166+
<nav class="topnav">
167+
<a href="./">← Proof Pack</a>
168+
<a href="./#de">DE_project section</a>
169+
</nav>
170+
171+
<h1>DV2.0 multi-branch — live demo</h1>
172+
<p class="lede">
173+
42-second silent recording of a Data Vault 2.0 multi-branch demo
174+
executing end-to-end against a self-hosted Kubernetes cluster on
175+
2026-05-23. <strong>Five branches</strong> (MSK / SPB / EKB / DXB / ALA),
176+
<strong>39 satellites</strong>, Business Vault MDM with per-branch RBAC,
177+
anonymized parquet cold tier in MinIO S3.
178+
</p>
179+
180+
<div class="player" id="player"></div>
181+
182+
<div class="meta">
183+
<span>silent recording · 42s · 130×35 terminal</span>
184+
<span class="dot">·</span>
185+
<span><a href="https://github.com/brownjuly2003-code/agentflow/tree/main/docs/dv2-multi-branch" target="_blank" rel="noopener">source on GitHub</a></span>
186+
<div class="play-actions">
187+
<a href="#" onclick="window.player.play(); return false;">play</a>
188+
<a href="#" onclick="window.player.pause(); return false;">pause</a>
189+
<a href="#" onclick="window.player.seek(0); window.player.play(); return false;">restart</a>
190+
</div>
191+
</div>
192+
193+
<section class="beats">
194+
<h2>What you see</h2>
195+
<div class="beats-grid">
196+
<div class="t">00:00</div>
197+
<div class="lab"><b>Cluster topology</b> · <code>kubectl get nodes --show-labels</code></div>
198+
<div>3 nodes labelled with <code>branch</code> / <code>nodepool</code> / <code>workload</code>; data-tier pods pinned by <code>nodeSelector</code>.</div>
199+
200+
<div class="t">00:08</div>
201+
<div class="lab"><b>Model surface</b> · <code>SELECT splitByString('_', name)[1], count() FROM system.tables</code></div>
202+
<div>bv 6, hub 8, lnk 8, sat 39 in <code>rv</code> — Data Vault 2.0 raw vault + business vault views.</div>
203+
204+
<div class="t">00:14</div>
205+
<div class="lab"><b>Multi-branch distribution</b> · split <code>record_source</code> from <code>hub_order</code></div>
206+
<div>msk 40.5 / spb 24.1 / ekb 14.5 / dxb 11.2 / ala 9.7 % — consistent hashing on <code>store_id</code>.</div>
207+
208+
<div class="t">00:22</div>
209+
<div class="lab"><b>Business Vault MDM</b> · per-branch PII + loyalty</div>
210+
<div>msk 800 / 800 / 640 (PII 100%, loyalty 80%); dxb 200 / 200 / 0 (no Bitrix24 in Dubai by design).</div>
211+
212+
<div class="t">00:30</div>
213+
<div class="lab"><b>Cold-offload</b> · <code>kubectl create job --from=cronjob/dv2-cold-offload-msk</code></div>
214+
<div>Anonymized parquet per branch in MinIO <code>local/cold-tier</code>. No PII columns in cold tier by contract.</div>
215+
216+
<div class="t">00:40</div>
217+
<div class="lab"><b>Closing</b> · <code>bash infrastructure/dv2/bootstrap.sh</code></div>
218+
<div>Everything in this recording rebuilds from a single command. No vendored state.</div>
219+
</div>
220+
</section>
221+
222+
<section class="context">
223+
<h2>Context</h2>
224+
<p>
225+
Mid-market fashion retailer: 5 locations, 3 jurisdictions, 6 source
226+
systems (1C + Bitrix24 + WMS Excel + site XML + WB/Ozon API).
227+
Production-shape DV2.0 modelling lives in Kubernetes-hosted ClickHouse
228+
25.5 + Postgres 17 + MinIO; Argo Workflows orchestrates the refresh
229+
DAG; dbt builds the mart layer; per-branch CDC fan-out via two
230+
Postgres databases and two CH <code>MaterializedPostgreSQL</code>
231+
databases proves operational isolation.
232+
</p>
233+
<p>
234+
The full architecture, query plans, and reproduction recipe are in
235+
<a href="https://github.com/brownjuly2003-code/agentflow/blob/main/docs/dv2-multi-branch/demo_evidence.md" target="_blank" rel="noopener">demo_evidence.md</a>
236+
in the AgentFlow repo. The 2-minute spoken pitch is in
237+
<a href="https://github.com/brownjuly2003-code/agentflow/blob/main/docs/dv2-multi-branch/pitch.md" target="_blank" rel="noopener">pitch.md</a>.
238+
</p>
239+
240+
<div class="stack">
241+
<span>Kubernetes (kind / upstream 1.35)</span>
242+
<span>ClickHouse 25.5</span>
243+
<span>Postgres 17</span>
244+
<span>MinIO S3</span>
245+
<span>Argo Workflows v3.5</span>
246+
<span>dbt</span>
247+
<span>MaterializedPostgreSQL CDC</span>
248+
<span>Data Vault 2.0</span>
249+
</div>
250+
</section>
251+
252+
<footer>
253+
Captured 2026-05-23 on the <code>hq-demo</code> cluster.
254+
Cast source · <a href="https://github.com/brownjuly2003-code/agentflow/blob/main/docs/dv2-multi-branch/demo.cast" target="_blank" rel="noopener">demo.cast</a>
255+
&nbsp;·&nbsp; runner · <a href="https://github.com/brownjuly2003-code/agentflow/blob/main/docs/dv2-multi-branch/demo_runner.sh" target="_blank" rel="noopener">demo_runner.sh</a>
256+
</footer>
257+
</main>
258+
259+
<script src="https://cdn.jsdelivr.net/npm/asciinema-player@3/dist/bundle/asciinema-player.min.js"></script>
260+
<script>
261+
window.player = AsciinemaPlayer.create('./dv2_demo.cast', document.getElementById('player'), {
262+
cols: 130,
263+
rows: 35,
264+
autoPlay: true,
265+
loop: true,
266+
idleTimeLimit: 2,
267+
theme: 'asciinema',
268+
fit: 'width'
269+
});
270+
</script>
271+
</body>
272+
</html>

‎index.html‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,7 @@ <h2>DE_project / AgentFlow</h2>
359359
</div>
360360
<div class="sec-links">
361361
<a class="pill primary" href="benchmarks/de_project-benchmark-2026-05-12.md" target="_blank">Locust benchmark <span class="arr">↗</span></a>
362+
<a class="pill" href="dv2_demo.html" target="_blank" rel="noopener">DV2.0 live demo · 42s <span class="arr">↗</span></a>
362363
</div>
363364
</div>
364365

0 commit comments

Comments
 (0)