semanticembed 0.7.1__tar.gz → 0.7.2__tar.gz

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.
Files changed (77) hide show
  1. {semanticembed-0.7.1 → semanticembed-0.7.2}/CHANGELOG.md +10 -0
  2. {semanticembed-0.7.1 → semanticembed-0.7.2}/PKG-INFO +1 -1
  3. semanticembed-0.7.2/notebooks/01_quickstart.ipynb +294 -0
  4. semanticembed-0.7.2/notebooks/02_dimensions.ipynb +327 -0
  5. semanticembed-0.7.2/notebooks/03_drift_detection.ipynb +216 -0
  6. semanticembed-0.7.2/notebooks/04_bring_your_own.ipynb +293 -0
  7. semanticembed-0.7.2/notebooks/05_ai_agent_pipelines.ipynb +287 -0
  8. semanticembed-0.7.2/notebooks/06_cicd_pipelines.ipynb +283 -0
  9. semanticembed-0.7.2/notebooks/07_opentelemetry.ipynb +346 -0
  10. {semanticembed-0.7.1 → semanticembed-0.7.2}/pyproject.toml +1 -1
  11. {semanticembed-0.7.1 → semanticembed-0.7.2}/src/semanticembed/__init__.py +1 -1
  12. {semanticembed-0.7.1 → semanticembed-0.7.2}/src/semanticembed/live.py +53 -9
  13. {semanticembed-0.7.1 → semanticembed-0.7.2}/tests/test_live.py +63 -0
  14. semanticembed-0.7.1/notebooks/01_quickstart.ipynb +0 -264
  15. semanticembed-0.7.1/notebooks/02_dimensions.ipynb +0 -309
  16. semanticembed-0.7.1/notebooks/03_drift_detection.ipynb +0 -195
  17. semanticembed-0.7.1/notebooks/04_bring_your_own.ipynb +0 -261
  18. semanticembed-0.7.1/notebooks/05_ai_agent_pipelines.ipynb +0 -257
  19. semanticembed-0.7.1/notebooks/06_cicd_pipelines.ipynb +0 -259
  20. semanticembed-0.7.1/notebooks/07_opentelemetry.ipynb +0 -343
  21. {semanticembed-0.7.1 → semanticembed-0.7.2}/.claude/skills/analyze/SKILL.md +0 -0
  22. {semanticembed-0.7.1 → semanticembed-0.7.2}/.github/workflows/publish.yml +0 -0
  23. {semanticembed-0.7.1 → semanticembed-0.7.2}/.gitignore +0 -0
  24. {semanticembed-0.7.1 → semanticembed-0.7.2}/LICENSE +0 -0
  25. {semanticembed-0.7.1 → semanticembed-0.7.2}/README.md +0 -0
  26. {semanticembed-0.7.1 → semanticembed-0.7.2}/docs/api_reference.md +0 -0
  27. {semanticembed-0.7.1 → semanticembed-0.7.2}/docs/dimensions.md +0 -0
  28. {semanticembed-0.7.1 → semanticembed-0.7.2}/docs/getting_started.md +0 -0
  29. {semanticembed-0.7.1 → semanticembed-0.7.2}/docs/input_format.md +0 -0
  30. {semanticembed-0.7.1 → semanticembed-0.7.2}/docs/license_keys.md +0 -0
  31. {semanticembed-0.7.1 → semanticembed-0.7.2}/docs/output_format.md +0 -0
  32. {semanticembed-0.7.1 → semanticembed-0.7.2}/examples/ai_agent_pipeline.json +0 -0
  33. {semanticembed-0.7.1 → semanticembed-0.7.2}/examples/cicd_pipeline.json +0 -0
  34. {semanticembed-0.7.1 → semanticembed-0.7.2}/examples/google_online_boutique.json +0 -0
  35. {semanticembed-0.7.1 → semanticembed-0.7.2}/examples/react/README.md +0 -0
  36. {semanticembed-0.7.1 → semanticembed-0.7.2}/examples/react/RadarChart.tsx +0 -0
  37. {semanticembed-0.7.1 → semanticembed-0.7.2}/examples/react/RiskTable.tsx +0 -0
  38. {semanticembed-0.7.1 → semanticembed-0.7.2}/examples/react/TopologySummary.tsx +0 -0
  39. {semanticembed-0.7.1 → semanticembed-0.7.2}/examples/react/useSemanticEmbed.ts +0 -0
  40. {semanticembed-0.7.1 → semanticembed-0.7.2}/examples/sample_pipeline.json +0 -0
  41. {semanticembed-0.7.1 → semanticembed-0.7.2}/examples/weaveworks_sock_shop.json +0 -0
  42. {semanticembed-0.7.1 → semanticembed-0.7.2}/notebooks/08_qwen_compression.ipynb +0 -0
  43. {semanticembed-0.7.1 → semanticembed-0.7.2}/notebooks/qwen_compression_cookbook.py +0 -0
  44. {semanticembed-0.7.1 → semanticembed-0.7.2}/skill/SETUP.md +0 -0
  45. {semanticembed-0.7.1 → semanticembed-0.7.2}/skill/SKILL.md +0 -0
  46. {semanticembed-0.7.1 → semanticembed-0.7.2}/skill/analyze.py +0 -0
  47. {semanticembed-0.7.1 → semanticembed-0.7.2}/src/semanticembed/agent/README.md +0 -0
  48. {semanticembed-0.7.1 → semanticembed-0.7.2}/src/semanticembed/agent/__init__.py +0 -0
  49. {semanticembed-0.7.1 → semanticembed-0.7.2}/src/semanticembed/agent/__main__.py +0 -0
  50. {semanticembed-0.7.1 → semanticembed-0.7.2}/src/semanticembed/agent/agent.py +0 -0
  51. {semanticembed-0.7.1 → semanticembed-0.7.2}/src/semanticembed/agent/gemini_agent.py +0 -0
  52. {semanticembed-0.7.1 → semanticembed-0.7.2}/src/semanticembed/client.py +0 -0
  53. {semanticembed-0.7.1 → semanticembed-0.7.2}/src/semanticembed/dedupe.py +0 -0
  54. {semanticembed-0.7.1 → semanticembed-0.7.2}/src/semanticembed/exceptions.py +0 -0
  55. {semanticembed-0.7.1 → semanticembed-0.7.2}/src/semanticembed/explain.py +0 -0
  56. {semanticembed-0.7.1 → semanticembed-0.7.2}/src/semanticembed/extract.py +0 -0
  57. {semanticembed-0.7.1 → semanticembed-0.7.2}/src/semanticembed/find_edges.py +0 -0
  58. {semanticembed-0.7.1 → semanticembed-0.7.2}/src/semanticembed/models.py +0 -0
  59. {semanticembed-0.7.1 → semanticembed-0.7.2}/tests/__init__.py +0 -0
  60. {semanticembed-0.7.1 → semanticembed-0.7.2}/tests/fixtures/autogen_app.py +0 -0
  61. {semanticembed-0.7.1 → semanticembed-0.7.2}/tests/fixtures/cdk_app.py +0 -0
  62. {semanticembed-0.7.1 → semanticembed-0.7.2}/tests/fixtures/crewai_app.py +0 -0
  63. {semanticembed-0.7.1 → semanticembed-0.7.2}/tests/fixtures/docker-compose.yml +0 -0
  64. {semanticembed-0.7.1 → semanticembed-0.7.2}/tests/fixtures/langgraph_app.py +0 -0
  65. {semanticembed-0.7.1 → semanticembed-0.7.2}/tests/fixtures/pulumi_app.py +0 -0
  66. {semanticembed-0.7.1 → semanticembed-0.7.2}/tests/fixtures/stack.yaml +0 -0
  67. {semanticembed-0.7.1 → semanticembed-0.7.2}/tests/fixtures/trace_jaeger.json +0 -0
  68. {semanticembed-0.7.1 → semanticembed-0.7.2}/tests/fixtures/trace_otlp.json +0 -0
  69. {semanticembed-0.7.1 → semanticembed-0.7.2}/tests/fixtures/trace_zipkin.json +0 -0
  70. {semanticembed-0.7.1 → semanticembed-0.7.2}/tests/test_aclient.py +0 -0
  71. {semanticembed-0.7.1 → semanticembed-0.7.2}/tests/test_client.py +0 -0
  72. {semanticembed-0.7.1 → semanticembed-0.7.2}/tests/test_dedupe.py +0 -0
  73. {semanticembed-0.7.1 → semanticembed-0.7.2}/tests/test_extract.py +0 -0
  74. {semanticembed-0.7.1 → semanticembed-0.7.2}/tests/test_extract_ai.py +0 -0
  75. {semanticembed-0.7.1 → semanticembed-0.7.2}/tests/test_extract_iac.py +0 -0
  76. {semanticembed-0.7.1 → semanticembed-0.7.2}/tests/test_extract_otel.py +0 -0
  77. {semanticembed-0.7.1 → semanticembed-0.7.2}/tests/test_skill.py +0 -0
@@ -2,6 +2,16 @@
2
2
 
3
3
  All notable changes to the SemanticEmbed SDK.
4
4
 
5
+ ## 0.7.2 — Live-connector retry
6
+
7
+ - All three live connectors (`from_dynatrace`, `from_honeycomb`, `from_datadog`)
8
+ now retry once with 0.5s backoff on transient failures: 502 / 503 / 504 /
9
+ ConnectError / ReadTimeout. 4xx responses (auth errors etc.) propagate
10
+ immediately. Matches the behavior already shipped on `encode()` / `aencode()`.
11
+ - Notebooks 02 / 03 / 04 / 06 refreshed to point at the v0.7.x APIs
12
+ (`cache=True`, `aencode_diff`, `find_edges`, `dedupe_edges`,
13
+ `from_github_actions`).
14
+
5
15
  ## 0.7.1 — Async surface
6
16
 
7
17
  - New: `aencode`, `aencode_file`, `aencode_diff` — async siblings of the
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: semanticembed
3
- Version: 0.7.1
3
+ Version: 0.7.2
4
4
  Summary: 6D structural intelligence for directed graphs. Six numbers per node. Sub-millisecond.
5
5
  Project-URL: Homepage, https://github.com/jmurray10/semanticembed-sdk
6
6
  Project-URL: Documentation, https://github.com/jmurray10/semanticembed-sdk
@@ -0,0 +1,294 @@
1
+ {
2
+ "nbformat": 4,
3
+ "nbformat_minor": 0,
4
+ "metadata": {
5
+ "colab": {
6
+ "provenance": [],
7
+ "name": "01_quickstart"
8
+ },
9
+ "kernelspec": {
10
+ "name": "python3",
11
+ "display_name": "Python 3"
12
+ },
13
+ "language_info": {
14
+ "name": "python"
15
+ }
16
+ },
17
+ "cells": [
18
+ {
19
+ "cell_type": "markdown",
20
+ "metadata": {},
21
+ "source": [
22
+ "# SemanticEmbed: Quickstart\n",
23
+ "\n",
24
+ "**6D structural intelligence for directed graphs.**\n",
25
+ "\n",
26
+ "This notebook walks you through:\n",
27
+ "1. Installing the SDK\n",
28
+ "2. Encoding a microservice graph\n",
29
+ "3. Reading the 6D output\n",
30
+ "4. Generating a structural risk report\n",
31
+ "\n",
32
+ "**No GPU needed. Runs in seconds.**\n",
33
+ "\n",
34
+ "[GitHub](https://github.com/jmurray10/semanticembed-sdk)\n"
35
+ ]
36
+ },
37
+ {
38
+ "cell_type": "code",
39
+ "metadata": {},
40
+ "source": [
41
+ "# Install the SDK\n",
42
+ "!pip install -q semanticembed\n",
43
+ "\n",
44
+ "from semanticembed import encode, report\n",
45
+ "print(\"SemanticEmbed installed.\")\n"
46
+ ],
47
+ "outputs": [],
48
+ "execution_count": null
49
+ },
50
+ {
51
+ "cell_type": "markdown",
52
+ "metadata": {},
53
+ "source": [
54
+ "---\n",
55
+ "## Step 1: Define a Graph\n",
56
+ "\n",
57
+ "The only input is an edge list -- a list of `(source, target)` pairs. This is Google's Online Boutique, an 11-service e-commerce application.\n"
58
+ ]
59
+ },
60
+ {
61
+ "cell_type": "code",
62
+ "metadata": {},
63
+ "source": [
64
+ "# Google Online Boutique -- 11 microservices\n",
65
+ "edges = [\n",
66
+ " (\"frontend\", \"ad-service\"),\n",
67
+ " (\"frontend\", \"cart-service\"),\n",
68
+ " (\"frontend\", \"checkout-service\"),\n",
69
+ " (\"frontend\", \"currency-service\"),\n",
70
+ " (\"frontend\", \"product-catalog-service\"),\n",
71
+ " (\"frontend\", \"recommendation-service\"),\n",
72
+ " (\"frontend\", \"shipping-service\"),\n",
73
+ " (\"checkout-service\", \"cart-service\"),\n",
74
+ " (\"checkout-service\", \"currency-service\"),\n",
75
+ " (\"checkout-service\", \"email-service\"),\n",
76
+ " (\"checkout-service\", \"payment-service\"),\n",
77
+ " (\"checkout-service\", \"product-catalog-service\"),\n",
78
+ " (\"checkout-service\", \"shipping-service\"),\n",
79
+ " (\"recommendation-service\",\"product-catalog-service\"),\n",
80
+ " (\"cart-service\", \"redis-cart\"),\n",
81
+ "]\n",
82
+ "\n",
83
+ "print(f\"Edges: {len(edges)}\")\n",
84
+ "for src, tgt in edges:\n",
85
+ " print(f\" {src} -> {tgt}\")\n"
86
+ ],
87
+ "outputs": [],
88
+ "execution_count": null
89
+ },
90
+ {
91
+ "cell_type": "markdown",
92
+ "metadata": {},
93
+ "source": [
94
+ "---\n",
95
+ "## Step 2: Compute the 6D Encoding\n",
96
+ "\n",
97
+ "One function call. Sub-millisecond.\n"
98
+ ]
99
+ },
100
+ {
101
+ "cell_type": "code",
102
+ "metadata": {},
103
+ "source": [
104
+ "result = encode(edges)\n",
105
+ "\n",
106
+ "print(f\"Encoding time: {result.encoding_time_ms:.2f}ms\")\n",
107
+ "print(f\"Nodes: {result.graph_info['nodes']}\")\n",
108
+ "print(f\"Edges: {result.graph_info['edges']}\")\n",
109
+ "print(f\"Max depth: {result.graph_info['max_depth']}\")\n",
110
+ "print()\n",
111
+ "print(result.table)\n"
112
+ ],
113
+ "outputs": [],
114
+ "execution_count": null
115
+ },
116
+ {
117
+ "cell_type": "markdown",
118
+ "metadata": {},
119
+ "source": [
120
+ "---\n",
121
+ "## Step 3: Understand the Output\n",
122
+ "\n",
123
+ "Each node now has six numbers -- its coordinates in 6-dimensional structural space:\n",
124
+ "\n",
125
+ "| Dimension | What It Measures |\n",
126
+ "|-----------|-----------------|\n",
127
+ "| **Depth** | Position in the execution pipeline (0.0 = entry, 1.0 = deepest) |\n",
128
+ "| **Independence** | Lateral redundancy at this pipeline stage (0.0 = only node at this depth) |\n",
129
+ "| **Hierarchy** | Module / group membership |\n",
130
+ "| **Throughput** | Fraction of total traffic flowing through this node |\n",
131
+ "| **Criticality** | Fraction of end-to-end paths that depend on this node |\n",
132
+ "| **Fanout** | Broadcaster (1.0) vs aggregator (0.0) |\n",
133
+ "\n",
134
+ "These six dimensions are mathematically independent. Knowing any five tells you nothing about the sixth.\n"
135
+ ]
136
+ },
137
+ {
138
+ "cell_type": "code",
139
+ "metadata": {},
140
+ "source": [
141
+ "# Inspect specific nodes\n",
142
+ "dim_names = [\"depth\", \"independence\", \"hierarchy\", \"throughput\", \"criticality\", \"fanout\"]\n",
143
+ "\n",
144
+ "for node in [\"frontend\", \"checkout-service\", \"redis-cart\"]:\n",
145
+ " v = result.vectors[node]\n",
146
+ " print(f\"\\n{node}:\")\n",
147
+ " for name, val in zip(dim_names, v):\n",
148
+ " bar = \"#\" * int(val * 30)\n",
149
+ " print(f\" {name:<15} {val:.3f} {bar}\")\n"
150
+ ],
151
+ "outputs": [],
152
+ "execution_count": null
153
+ },
154
+ {
155
+ "cell_type": "markdown",
156
+ "metadata": {},
157
+ "source": [
158
+ "---\n",
159
+ "## Step 4: Structural Risk Report\n",
160
+ "\n",
161
+ "The encoding identifies architectural risks purely from topology. No runtime data, no historical incidents.\n"
162
+ ]
163
+ },
164
+ {
165
+ "cell_type": "code",
166
+ "metadata": {},
167
+ "source": [
168
+ "risk = report(result)\n",
169
+ "print(risk)\n"
170
+ ],
171
+ "outputs": [],
172
+ "execution_count": null
173
+ },
174
+ {
175
+ "cell_type": "markdown",
176
+ "metadata": {},
177
+ "source": [
178
+ "---\n",
179
+ "## Step 5: Try a Different Graph\n",
180
+ "\n",
181
+ "Same SDK, different architecture. Weaveworks Sock Shop -- 14 services on Kubernetes.\n"
182
+ ]
183
+ },
184
+ {
185
+ "cell_type": "code",
186
+ "metadata": {},
187
+ "source": [
188
+ "sock_shop = [\n",
189
+ " (\"edge-router\", \"frontend\"),\n",
190
+ " (\"frontend\", \"catalogue\"),\n",
191
+ " (\"frontend\", \"orders\"),\n",
192
+ " (\"frontend\", \"user\"),\n",
193
+ " (\"frontend\", \"carts\"),\n",
194
+ " (\"orders\", \"shipping\"),\n",
195
+ " (\"orders\", \"payment\"),\n",
196
+ " (\"orders\", \"carts\"),\n",
197
+ " (\"orders\", \"user\"),\n",
198
+ " (\"catalogue\", \"catalogue-db\"),\n",
199
+ " (\"carts\", \"carts-db\"),\n",
200
+ " (\"orders\", \"orders-db\"),\n",
201
+ " (\"user\", \"user-db\"),\n",
202
+ " (\"shipping\", \"rabbitmq\"),\n",
203
+ " (\"queue-master\", \"rabbitmq\"),\n",
204
+ "]\n",
205
+ "\n",
206
+ "result_shop = encode(sock_shop)\n",
207
+ "print(result_shop.table)\n",
208
+ "print()\n",
209
+ "print(report(result_shop))\n"
210
+ ],
211
+ "outputs": [],
212
+ "execution_count": null
213
+ },
214
+ {
215
+ "cell_type": "markdown",
216
+ "metadata": {},
217
+ "source": [
218
+ "---\n",
219
+ "## Step 6: Your Own Graph\n",
220
+ "\n",
221
+ "Paste your edge list below. Any directed graph -- microservices, data pipelines, CI/CD workflows, agent orchestrations.\n"
222
+ ]
223
+ },
224
+ {
225
+ "cell_type": "code",
226
+ "metadata": {},
227
+ "source": [
228
+ "# Replace with your own edges\n",
229
+ "my_edges = [\n",
230
+ " (\"service-a\", \"service-b\"),\n",
231
+ " (\"service-a\", \"service-c\"),\n",
232
+ " (\"service-b\", \"service-d\"),\n",
233
+ " (\"service-c\", \"service-d\"),\n",
234
+ " (\"service-d\", \"service-e\"),\n",
235
+ "]\n",
236
+ "\n",
237
+ "my_result = encode(my_edges)\n",
238
+ "print(my_result.table)\n",
239
+ "print()\n",
240
+ "print(report(my_result))\n"
241
+ ],
242
+ "outputs": [],
243
+ "execution_count": null
244
+ },
245
+ {
246
+ "cell_type": "markdown",
247
+ "metadata": {},
248
+ "source": [
249
+ "---\n",
250
+ "## What's Next?\n",
251
+ "\n",
252
+ "- **[02 - Dimensions Deep Dive](https://colab.research.google.com/github/jmurray10/semanticembed-sdk/blob/main/notebooks/02_dimensions.ipynb)** -- what each dimension means with worked examples\n",
253
+ "- **[03 - Drift Detection](https://colab.research.google.com/github/jmurray10/semanticembed-sdk/blob/main/notebooks/03_drift_detection.ipynb)** -- compare graph versions, detect structural changes\n",
254
+ "- **[04 - Bring Your Own Graph](https://colab.research.google.com/github/jmurray10/semanticembed-sdk/blob/main/notebooks/04_bring_your_own.ipynb)** -- load from JSON, OTel traces, or Kubernetes\n",
255
+ "\n",
256
+ "**Free tier:** 50 nodes. **Paid tier:** unlimited nodes + continuous monitoring.\n",
257
+ "\n",
258
+ "[GitHub](https://github.com/jmurray10/semanticembed-sdk) | [Contact](mailto:jeffmurr@seas.upenn.edu)\n",
259
+ "\n",
260
+ "*Patent pending. Application #63/994,075.*\n"
261
+ ]
262
+ },
263
+ {
264
+ "cell_type": "markdown",
265
+ "metadata": {},
266
+ "source": [
267
+ "## Auto-discover edges from your repo\n",
268
+ "\n",
269
+ "The SDK parses 14 different infrastructure formats \u2014 docker-compose, Kubernetes,\n",
270
+ "Terraform, CloudFormation, AWS CDK, Pulumi, GitHub Actions, package.json,\n",
271
+ "pyproject.toml, OpenTelemetry traces, Python imports, and the LangGraph /\n",
272
+ "CrewAI / AutoGen agent frameworks. `extract.from_directory()` auto-detects\n",
273
+ "whatever's there:\n",
274
+ "\n",
275
+ "```python\n",
276
+ "import semanticembed as se\n",
277
+ "\n",
278
+ "edges, sources = se.extract.from_directory(\".\")\n",
279
+ "print(f\"Found {len(edges)} edges from {sources}\")\n",
280
+ "\n",
281
+ "result = se.encode(edges)\n",
282
+ "```\n",
283
+ "\n",
284
+ "For *running* infra (not just repo files), see `semanticembed.live`:\n",
285
+ "\n",
286
+ "```python\n",
287
+ "edges = se.live.from_dynatrace(env_url=..., api_token=...)\n",
288
+ "edges = se.live.from_honeycomb(dataset=..., api_key=...)\n",
289
+ "edges = se.live.from_datadog(api_key=..., app_key=...)\n",
290
+ "```\n"
291
+ ]
292
+ }
293
+ ]
294
+ }
@@ -0,0 +1,327 @@
1
+ {
2
+ "nbformat": 4,
3
+ "nbformat_minor": 0,
4
+ "metadata": {
5
+ "colab": {
6
+ "provenance": [],
7
+ "name": "02_dimensions"
8
+ },
9
+ "kernelspec": {
10
+ "name": "python3",
11
+ "display_name": "Python 3"
12
+ },
13
+ "language_info": {
14
+ "name": "python"
15
+ }
16
+ },
17
+ "cells": [
18
+ {
19
+ "cell_type": "markdown",
20
+ "metadata": {},
21
+ "source": [
22
+ "# SemanticEmbed: The Six Dimensions\n",
23
+ "\n",
24
+ "A deep dive into what each of the six structural measurements means, why they matter, and how to read them.\n",
25
+ "\n",
26
+ "[GitHub](https://github.com/jmurray10/semanticembed-sdk)\n"
27
+ ]
28
+ },
29
+ {
30
+ "cell_type": "code",
31
+ "metadata": {},
32
+ "source": [
33
+ "!pip install -q semanticembed\n",
34
+ "from semanticembed import encode, report\n",
35
+ "print(\"Ready.\")\n"
36
+ ],
37
+ "outputs": [],
38
+ "execution_count": null
39
+ },
40
+ {
41
+ "cell_type": "markdown",
42
+ "metadata": {},
43
+ "source": [
44
+ "---\n",
45
+ "## The Encoding at a Glance\n",
46
+ "\n",
47
+ "Every node in a directed graph gets six numbers. Together they form a coordinate vector in 6-dimensional Euclidean space that fully describes the node's structural role.\n",
48
+ "\n",
49
+ "| # | Dimension | What It Measures | Range |\n",
50
+ "|---|-----------|-----------------|-------|\n",
51
+ "| 1 | **Depth** | Pipeline position (entry to sink) | 0.0 -- 1.0 |\n",
52
+ "| 2 | **Independence** | Lateral redundancy at same stage | 0.0 -- 1.0 |\n",
53
+ "| 3 | **Hierarchy** | Module / group membership | 0.0 -- 1.0 |\n",
54
+ "| 4 | **Throughput** | Share of total traffic | 0.0 -- 1.0 |\n",
55
+ "| 5 | **Criticality** | Share of end-to-end paths | 0.0 -- 1.0 |\n",
56
+ "| 6 | **Fanout** | Broadcaster (1.0) vs aggregator (0.0) | 0.0 -- 1.0 |\n",
57
+ "\n",
58
+ "These are mathematically independent. Knowing any five tells you nothing about the sixth.\n"
59
+ ]
60
+ },
61
+ {
62
+ "cell_type": "markdown",
63
+ "metadata": {},
64
+ "source": [
65
+ "---\n",
66
+ "## Dimension 1: Depth\n",
67
+ "\n",
68
+ "**What:** Where a node sits in the execution pipeline -- from entry point (0.0) to deepest sink (1.0).\n",
69
+ "\n",
70
+ "**Why it matters:** Depth tells you the blast radius direction. A failure at depth 0.0 cascades forward through the entire graph. A failure at depth 1.0 affects nothing downstream.\n"
71
+ ]
72
+ },
73
+ {
74
+ "cell_type": "code",
75
+ "metadata": {},
76
+ "source": [
77
+ "# A simple pipeline -- depth increases left to right\n",
78
+ "pipeline = [\n",
79
+ " (\"ingestion\", \"validation\"),\n",
80
+ " (\"validation\", \"transform\"),\n",
81
+ " (\"transform\", \"enrichment\"),\n",
82
+ " (\"enrichment\", \"storage\"),\n",
83
+ "]\n",
84
+ "\n",
85
+ "result = encode(pipeline)\n",
86
+ "print(\"LINEAR PIPELINE -- depth increases with each hop\")\n",
87
+ "print(\"=\" * 60)\n",
88
+ "for node, v in sorted(result.vectors.items(), key=lambda x: x[1][0]):\n",
89
+ " print(f\" {node:<15} depth={v[0]:.3f}\")\n"
90
+ ],
91
+ "outputs": [],
92
+ "execution_count": null
93
+ },
94
+ {
95
+ "cell_type": "markdown",
96
+ "metadata": {},
97
+ "source": [
98
+ "---\n",
99
+ "## Dimension 2: Independence\n",
100
+ "\n",
101
+ "**What:** How many other nodes exist at the same depth level. Measures lateral redundancy.\n",
102
+ "\n",
103
+ "**Why it matters:** Independence = 0.0 means this node is the ONLY node at its depth. There is no parallel alternative. It is a structural chokepoint regardless of whether it is healthy today.\n",
104
+ "\n",
105
+ "**This dimension has no equivalent in standard graph centrality.** Maximum correlation with all 10 standard centrality measures across real applications: |r| = 0.369.\n"
106
+ ]
107
+ },
108
+ {
109
+ "cell_type": "code",
110
+ "metadata": {},
111
+ "source": [
112
+ "# Wide fan-out -- services at depth 1 have high independence\n",
113
+ "wide = [\n",
114
+ " (\"gateway\", \"service-a\"),\n",
115
+ " (\"gateway\", \"service-b\"),\n",
116
+ " (\"gateway\", \"service-c\"),\n",
117
+ " (\"gateway\", \"service-d\"),\n",
118
+ " (\"service-a\", \"db\"),\n",
119
+ " (\"service-b\", \"db\"),\n",
120
+ " (\"service-c\", \"db\"),\n",
121
+ " (\"service-d\", \"db\"),\n",
122
+ "]\n",
123
+ "\n",
124
+ "result = encode(wide)\n",
125
+ "print(\"WIDE ARCHITECTURE -- high independence at depth 1\")\n",
126
+ "print(\"=\" * 60)\n",
127
+ "for node, v in sorted(result.vectors.items(), key=lambda x: x[1][0]):\n",
128
+ " print(f\" {node:<15} depth={v[0]:.3f} independence={v[1]:.3f}\")\n"
129
+ ],
130
+ "outputs": [],
131
+ "execution_count": null
132
+ },
133
+ {
134
+ "cell_type": "markdown",
135
+ "metadata": {},
136
+ "source": [
137
+ "---\n",
138
+ "## Dimension 3: Hierarchy\n",
139
+ "\n",
140
+ "**What:** Which module or logical group a node belongs to.\n",
141
+ "\n",
142
+ "**Why it matters:** Hierarchy captures community structure. Nodes in the same module have similar hierarchy values. Useful for detecting cross-module dependencies and module boundary violations.\n"
143
+ ]
144
+ },
145
+ {
146
+ "cell_type": "code",
147
+ "metadata": {},
148
+ "source": [
149
+ "# Two separate modules feeding into a shared database\n",
150
+ "two_modules = [\n",
151
+ " (\"orders-api\", \"orders-processor\"),\n",
152
+ " (\"orders-processor\", \"orders-db\"),\n",
153
+ " (\"users-api\", \"users-processor\"),\n",
154
+ " (\"users-processor\", \"users-db\"),\n",
155
+ " (\"orders-processor\", \"shared-cache\"),\n",
156
+ " (\"users-processor\", \"shared-cache\"),\n",
157
+ "]\n",
158
+ "\n",
159
+ "result = encode(two_modules)\n",
160
+ "print(\"TWO-MODULE ARCHITECTURE\")\n",
161
+ "print(\"=\" * 60)\n",
162
+ "for node, v in sorted(result.vectors.items(), key=lambda x: x[1][2]):\n",
163
+ " print(f\" {node:<20} hierarchy={v[2]:.3f}\")\n"
164
+ ],
165
+ "outputs": [],
166
+ "execution_count": null
167
+ },
168
+ {
169
+ "cell_type": "markdown",
170
+ "metadata": {},
171
+ "source": [
172
+ "---\n",
173
+ "## Dimension 4: Throughput\n",
174
+ "\n",
175
+ "**What:** What fraction of total traffic flows through this node.\n",
176
+ "\n",
177
+ "**Why it matters:** High throughput + low independence = hidden bottleneck. The node carries a disproportionate share of traffic with no backup.\n",
178
+ "\n",
179
+ "Independent of depth: a deep node can have high or low throughput.\n"
180
+ ]
181
+ },
182
+ {
183
+ "cell_type": "code",
184
+ "metadata": {},
185
+ "source": [
186
+ "# Hub-and-spoke -- the hub has high throughput\n",
187
+ "hub_spoke = [\n",
188
+ " (\"client-1\", \"api-hub\"),\n",
189
+ " (\"client-2\", \"api-hub\"),\n",
190
+ " (\"client-3\", \"api-hub\"),\n",
191
+ " (\"api-hub\", \"backend-a\"),\n",
192
+ " (\"api-hub\", \"backend-b\"),\n",
193
+ " (\"api-hub\", \"backend-c\"),\n",
194
+ " (\"backend-a\", \"database\"),\n",
195
+ " (\"backend-b\", \"database\"),\n",
196
+ " (\"backend-c\", \"database\"),\n",
197
+ "]\n",
198
+ "\n",
199
+ "result = encode(hub_spoke)\n",
200
+ "print(\"HUB-AND-SPOKE -- hub carries most traffic\")\n",
201
+ "print(\"=\" * 60)\n",
202
+ "for node, v in sorted(result.vectors.items(), key=lambda x: -x[1][3]):\n",
203
+ " print(f\" {node:<15} throughput={v[3]:.3f} independence={v[1]:.3f}\")\n"
204
+ ],
205
+ "outputs": [],
206
+ "execution_count": null
207
+ },
208
+ {
209
+ "cell_type": "markdown",
210
+ "metadata": {},
211
+ "source": [
212
+ "---\n",
213
+ "## Dimension 5: Criticality\n",
214
+ "\n",
215
+ "**What:** How many end-to-end paths through the graph depend on this node.\n",
216
+ "\n",
217
+ "**Why it matters:** A node with criticality 0.5 sits on half of all paths. If it fails, half of all end-to-end flows break. This is independent of throughput -- a low-traffic node can be highly critical if it bridges two large subgraphs.\n"
218
+ ]
219
+ },
220
+ {
221
+ "cell_type": "code",
222
+ "metadata": {},
223
+ "source": [
224
+ "# Diamond shape -- the middle nodes are critical bridges\n",
225
+ "diamond = [\n",
226
+ " (\"source\", \"left-branch\"),\n",
227
+ " (\"source\", \"right-branch\"),\n",
228
+ " (\"left-branch\", \"merge-point\"),\n",
229
+ " (\"right-branch\", \"merge-point\"),\n",
230
+ " (\"merge-point\", \"sink-a\"),\n",
231
+ " (\"merge-point\", \"sink-b\"),\n",
232
+ " (\"merge-point\", \"sink-c\"),\n",
233
+ "]\n",
234
+ "\n",
235
+ "result = encode(diamond)\n",
236
+ "print(\"DIAMOND -- merge-point bridges source to all sinks\")\n",
237
+ "print(\"=\" * 60)\n",
238
+ "for node, v in sorted(result.vectors.items(), key=lambda x: -x[1][4]):\n",
239
+ " print(f\" {node:<15} criticality={v[4]:.3f} fanout={v[5]:.3f}\")\n"
240
+ ],
241
+ "outputs": [],
242
+ "execution_count": null
243
+ },
244
+ {
245
+ "cell_type": "markdown",
246
+ "metadata": {},
247
+ "source": [
248
+ "---\n",
249
+ "## Dimension 6: Fanout\n",
250
+ "\n",
251
+ "**What:** Whether a node amplifies (broadcasts to many) or aggregates (collects from many). Out-degree / total degree.\n",
252
+ "\n",
253
+ "**Why it matters:** High fanout = amplification risk. If this node fails or slows, the impact multiplies across all downstream dependents. Low fanout = convergence sink. Many services depend on this single aggregation point.\n"
254
+ ]
255
+ },
256
+ {
257
+ "cell_type": "code",
258
+ "metadata": {},
259
+ "source": [
260
+ "# Contrasting broadcaster vs aggregator\n",
261
+ "fanout_example = [\n",
262
+ " (\"broadcaster\", \"target-1\"),\n",
263
+ " (\"broadcaster\", \"target-2\"),\n",
264
+ " (\"broadcaster\", \"target-3\"),\n",
265
+ " (\"broadcaster\", \"target-4\"),\n",
266
+ " (\"broadcaster\", \"target-5\"),\n",
267
+ " (\"source-1\", \"aggregator\"),\n",
268
+ " (\"source-2\", \"aggregator\"),\n",
269
+ " (\"source-3\", \"aggregator\"),\n",
270
+ " (\"source-4\", \"aggregator\"),\n",
271
+ " (\"source-5\", \"aggregator\"),\n",
272
+ "]\n",
273
+ "\n",
274
+ "result = encode(fanout_example)\n",
275
+ "print(\"BROADCASTER vs AGGREGATOR\")\n",
276
+ "print(\"=\" * 60)\n",
277
+ "for node in [\"broadcaster\", \"aggregator\"]:\n",
278
+ " v = result.vectors[node]\n",
279
+ " label = \"broadcasts to 5\" if v[5] > 0.5 else \"collects from 5\"\n",
280
+ " print(f\" {node:<15} fanout={v[5]:.3f} ({label})\")\n"
281
+ ],
282
+ "outputs": [],
283
+ "execution_count": null
284
+ },
285
+ {
286
+ "cell_type": "markdown",
287
+ "metadata": {},
288
+ "source": [
289
+ "---\n",
290
+ "## Structural Risk Patterns\n",
291
+ "\n",
292
+ "Combinations of dimension values reveal risk:\n",
293
+ "\n",
294
+ "| Pattern | Dimensions | Risk |\n",
295
+ "|---------|-----------|------|\n",
296
+ "| **Amplification risk** | High fanout + high criticality | Failure cascades to many services across many paths |\n",
297
+ "| **Convergence sink** | Low independence + low fanout | Many services depend on one aggregation point |\n",
298
+ "| **Structural SPOF** | Low independence + high criticality | Only node at its depth, on most paths |\n",
299
+ "| **Hidden bottleneck** | High throughput + low independence | Carries most traffic with no redundancy |\n",
300
+ "\n",
301
+ "The risk report detects these automatically. See [01 - Quickstart](https://colab.research.google.com/github/jmurray10/semanticembed-sdk/blob/main/notebooks/01_quickstart.ipynb) for the full walkthrough.\n",
302
+ "\n",
303
+ "---\n",
304
+ "\n",
305
+ "*Patent pending. Application #63/994,075.*\n"
306
+ ]
307
+ },
308
+ {
309
+ "cell_type": "markdown",
310
+ "metadata": {},
311
+ "source": [
312
+ "## Cache repeat encodes during exploration\n",
313
+ "\n",
314
+ "When you're iterating on the same edge list (tweaking visualizations, building\n",
315
+ "slides), set ``cache=True`` to skip the HTTP round trip on repeat calls:\n",
316
+ "\n",
317
+ "```python\n",
318
+ "result = se.encode(edges, cache=True) # 1st call: HTTP\n",
319
+ "result = se.encode(edges, cache=True) # 2nd call: 0ms, no HTTP\n",
320
+ "se.clear_encode_cache() # explicit eviction if needed\n",
321
+ "```\n",
322
+ "\n",
323
+ "The cache key is order-independent, so reordering the same edges still hits.\n"
324
+ ]
325
+ }
326
+ ]
327
+ }