<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>rackattack</title><link>https://lex00.github.io/rackattack/</link><description>Recent content on rackattack</description><generator>Hugo</generator><language>en-us</language><atom:link href="https://lex00.github.io/rackattack/index.xml" rel="self" type="application/rss+xml"/><item><title>Quick start</title><link>https://lex00.github.io/rackattack/quickstart/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://lex00.github.io/rackattack/quickstart/</guid><description>&lt;h1 id="quick-start--generate-a-datacenter-then-ask-an-agent"&gt;Quick start — generate a datacenter, then ask an agent&lt;a class="anchor" href="#quick-start--generate-a-datacenter-then-ask-an-agent"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;From an empty checkout to a &lt;strong&gt;browser-viewable gallery of live diagrams&lt;/strong&gt; and an
&lt;strong&gt;agent answering plain-language questions over MCP&lt;/strong&gt;. About five minutes.&lt;/p&gt;
&lt;h2 id="0-prerequisites"&gt;0. Prerequisites&lt;a class="anchor" href="#0-prerequisites"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Go 1.25&lt;/strong&gt;, &lt;strong&gt;Docker&lt;/strong&gt; (for the CockroachDB dev node), and &lt;strong&gt;&lt;code&gt;just&lt;/code&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Graphviz&lt;/strong&gt; — the one non-obvious dependency. The blast-radius frame shells out
to &lt;code&gt;dot&lt;/code&gt;; without it that hero frame fails (the other four screens are pure Go).&lt;/p&gt;</description></item><item><title>Architecture</title><link>https://lex00.github.io/rackattack/architecture/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://lex00.github.io/rackattack/architecture/</guid><description>&lt;h1 id="architecture"&gt;Architecture&lt;a class="anchor" href="#architecture"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;rackattack is &lt;strong&gt;one service core behind four interfaces&lt;/strong&gt;. gRPC is the primary
product contract; REST comes essentially for free via grpc-gateway over the same
proto; GraphQL (gqlgen) is a third HTTP transport; and MCP is a thin secondary
adapter (built last) that maps the same core to agent tools. All four speak to a
single core that does validation, complex filtering, aggregation, and bulk
operations, then walks the infra graph and renders the result.&lt;/p&gt;</description></item><item><title>Data model &amp; schema</title><link>https://lex00.github.io/rackattack/data-model/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://lex00.github.io/rackattack/data-model/</guid><description>&lt;h1 id="data-model--schema"&gt;Data model &amp;amp; schema&lt;a class="anchor" href="#data-model--schema"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;The infra graph is &lt;strong&gt;16 CockroachDB tables&lt;/strong&gt; across these concerns: a spatial
hierarchy, devices with their ports and pluggable optical transceivers, a power
chain with A/B redundancy, physical cabling, cooling, and logical fabric links.
A 17th table — &lt;code&gt;audit_log&lt;/code&gt; — is operational rather than part of the graph (it
records change-data-capture events; see &lt;a href="../audit/"&gt;Audit &amp;amp; CDC&lt;/a&gt;). The diagram
below reflects the migrations in
&lt;a href="https://github.com/lex00/rackattack/tree/main/internal/schema/migrations"&gt;&lt;code&gt;internal/schema/migrations&lt;/code&gt;&lt;/a&gt;
exactly.&lt;/p&gt;
&lt;figure class="diagram"&gt;
 &lt;img src="https://lex00.github.io/rackattack/diagrams/d2-schema.svg"
 alt="Entity/relationship diagram of the 17-table schema" loading="lazy"&gt;&lt;figcaption&gt;&lt;em&gt;Entity/relationship diagram of the 17-table schema&lt;/em&gt;&lt;/figcaption&gt;&lt;/figure&gt;

&lt;h2 id="spatial-hierarchy"&gt;Spatial hierarchy&lt;a class="anchor" href="#spatial-hierarchy"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;sites → floors → rack_rows → racks → rack_units → devices → ports&lt;/code&gt;. Each level
references its parent; &lt;code&gt;racks&lt;/code&gt; also carry a &lt;code&gt;cooling_budget_watts&lt;/code&gt;, and &lt;code&gt;devices&lt;/code&gt;
carry &lt;code&gt;watts&lt;/code&gt; and &lt;code&gt;heat_watts&lt;/code&gt; so power and thermal rollups have real numbers.&lt;/p&gt;</description></item><item><title>Rendering</title><link>https://lex00.github.io/rackattack/rendering/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://lex00.github.io/rackattack/rendering/</guid><description>&lt;h1 id="rendering--the-differentiator"&gt;Rendering — the differentiator&lt;a class="anchor" href="#rendering--the-differentiator"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;A GUI is a persistent app you navigate; rackattack cuts it. A &lt;strong&gt;visualization is
just an artifact&lt;/strong&gt; the service renders on demand and hands back. The agent is the
input, a generated artifact is the output: you ask a question in plain language
and rackattack renders &lt;em&gt;exactly the picture that answers it&lt;/em&gt; — blast radius with
only the affected racks lit red, survivors green, everything else dimmed. The
diagram is an &lt;strong&gt;answer, not a map&lt;/strong&gt;.&lt;/p&gt;</description></item><item><title>MCP (agent interface)</title><link>https://lex00.github.io/rackattack/mcp/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://lex00.github.io/rackattack/mcp/</guid><description>&lt;h1 id="mcp-agent-interface"&gt;MCP (agent interface)&lt;a class="anchor" href="#mcp-agent-interface"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;MCP is rackattack&amp;rsquo;s &lt;strong&gt;front door for an LLM agent&lt;/strong&gt;. The
&lt;a href="https://modelcontextprotocol.io"&gt;Model Context Protocol&lt;/a&gt; adapter is a thin
secondary transport — alongside gRPC, REST, and GraphQL — that maps the same
service core to agent tools. It runs over &lt;strong&gt;JSON-RPC on stdio&lt;/strong&gt;, so an agent
launches &lt;code&gt;rackattack mcp&lt;/code&gt; as a subprocess and calls tools directly; no network
port, no auth handshake.&lt;/p&gt;
&lt;p&gt;Every screen-generating tool returns &lt;strong&gt;structured data &lt;em&gt;and&lt;/em&gt; a rendered diagram&lt;/strong&gt;
in one reply (the diagram comes back base64-encoded under &lt;code&gt;render.image&lt;/code&gt;), so an
agent gets both the facts and the picture from a single call.&lt;/p&gt;</description></item><item><title>CLI reference</title><link>https://lex00.github.io/rackattack/cli/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://lex00.github.io/rackattack/cli/</guid><description>&lt;h1 id="cli-reference"&gt;CLI reference&lt;a class="anchor" href="#cli-reference"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;The &lt;code&gt;rackattack&lt;/code&gt; binary is a single CLI with six subcommands. Runtime behaviour
is configured through environment variables (see &lt;a href="../configuration/"&gt;Configuration&lt;/a&gt;);
the flags below control per-invocation inputs.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;rackattack [command]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; serve Run the gRPC service and the REST (grpc-gateway) endpoint
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mcp Run the MCP adapter over stdio
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; migrate Apply database migrations
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; fleet Generate a synthetic datacenter fleet
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; example Generate a sample fleet and a guided-tour gallery
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; query Run a single query and print a summary
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -h, --help help for rackattack
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -v, --version version for rackattack&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Every subcommand reads &lt;code&gt;DATABASE_URL&lt;/code&gt; (default
&lt;code&gt;postgres://root@localhost:26257/rackattack?sslmode=disable&lt;/code&gt;). All commands that
need a schema (&lt;code&gt;serve&lt;/code&gt;, &lt;code&gt;fleet&lt;/code&gt;, &lt;code&gt;example&lt;/code&gt;) auto-migrate first, so a separate
&lt;code&gt;migrate&lt;/code&gt; run is optional.&lt;/p&gt;</description></item><item><title>API surface</title><link>https://lex00.github.io/rackattack/api/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://lex00.github.io/rackattack/api/</guid><description>&lt;h1 id="api-surface"&gt;API surface&lt;a class="anchor" href="#api-surface"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;rackattack is &lt;strong&gt;one service core behind four interfaces&lt;/strong&gt;. gRPC is the primary
product contract. REST is generated from the same proto via grpc-gateway and
served in-process. GraphQL (gqlgen, schema-first) is a third HTTP transport over
the same core. MCP is a thin secondary adapter mapping the core to agent tools.&lt;/p&gt;
&lt;p&gt;All four resolve through the single service core, so authorization, caching, and
audit apply uniformly no matter which door a request comes in.&lt;/p&gt;</description></item><item><title>Configuration</title><link>https://lex00.github.io/rackattack/configuration/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://lex00.github.io/rackattack/configuration/</guid><description>&lt;h1 id="configuration"&gt;Configuration&lt;a class="anchor" href="#configuration"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Every runtime setting is an environment variable. The binary reads them at
startup; there is no config file. Defaults are tuned for a one-command local
evaluation (single-node CockroachDB, auth off) — &lt;strong&gt;review the production-relevant
rows before exposing rackattack&lt;/strong&gt; (see &lt;a href="../security/"&gt;Security &amp;amp; auth&lt;/a&gt;,
&lt;a href="../deployment/"&gt;Deployment&lt;/a&gt;, and the production design in
&lt;a href="https://github.com/lex00/rackattack/blob/main/docs/production-deployment.md"&gt;&lt;code&gt;docs/production-deployment.md&lt;/code&gt;&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Booleans accept &lt;code&gt;1&lt;/code&gt; / &lt;code&gt;true&lt;/code&gt; / &lt;code&gt;yes&lt;/code&gt; / &lt;code&gt;on&lt;/code&gt; (and their negatives).&lt;/p&gt;
&lt;h2 id="server--database"&gt;Server &amp;amp; database&lt;a class="anchor" href="#server--database"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Env&lt;/th&gt;
					&lt;th&gt;Meaning&lt;/th&gt;
					&lt;th&gt;Default&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;DATABASE_URL&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;CockroachDB (Postgres-compatible) connection string. Used by every subcommand.&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;postgres://root@localhost:26257/rackattack?sslmode=disable&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;GRPC_ADDR&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Listen address for the gRPC server (&lt;code&gt;serve&lt;/code&gt;).&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;:8080&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;HTTP_ADDR&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Listen address for the HTTP server (&lt;code&gt;serve&lt;/code&gt;) — REST gateway, GraphQL, &lt;code&gt;/metrics&lt;/code&gt;, and &lt;code&gt;/audit/*&lt;/code&gt;.&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;:8081&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;DB_MAX_CONNS&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Max size of the pgx connection pool — the knob to tune under concurrent load. Can also be set with a &lt;code&gt;pool_max_conns&lt;/code&gt; query param on &lt;code&gt;DATABASE_URL&lt;/code&gt;.&lt;/td&gt;
					&lt;td&gt;pgx default: &lt;code&gt;max(4, GOMAXPROCS)&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;DB_TLS_ROOT_CERT&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Path to the CA certificate (PEM) used to verify the CockroachDB server cert under &lt;code&gt;sslmode=verify-full&lt;/code&gt;, when you&amp;rsquo;d rather not put &lt;code&gt;sslrootcert=&lt;/code&gt; in &lt;code&gt;DATABASE_URL&lt;/code&gt; (e.g. a mounted k8s Secret). Ignored if the URL already sets &lt;code&gt;sslrootcert&lt;/code&gt;.&lt;/td&gt;
					&lt;td&gt;unset&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;SHUTDOWN_GRACE_PERIOD&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;On &lt;code&gt;SIGTERM&lt;/code&gt;/&lt;code&gt;SIGINT&lt;/code&gt;, &lt;code&gt;serve&lt;/code&gt; stops accepting new work and drains in-flight gRPC RPCs and HTTP requests within this budget (Go duration) before exiting. Keep it under the pod&amp;rsquo;s &lt;code&gt;terminationGracePeriodSeconds&lt;/code&gt; (30s).&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;25s&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;RACKATTACK_ENV&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Set to &lt;code&gt;production&lt;/code&gt; (or &lt;code&gt;prod&lt;/code&gt;) to enable the production guardrail: &lt;code&gt;serve&lt;/code&gt; &lt;strong&gt;refuses to boot&lt;/strong&gt; with edge auth disabled, or a &lt;code&gt;DATABASE_URL&lt;/code&gt; that doesn&amp;rsquo;t verify TLS (anything other than &lt;code&gt;sslmode=verify-full&lt;/code&gt; or &lt;code&gt;verify-ca&lt;/code&gt; — &lt;code&gt;disable&lt;/code&gt;/&lt;code&gt;allow&lt;/code&gt;/&lt;code&gt;prefer&lt;/code&gt;/&lt;code&gt;require&lt;/code&gt;/unset all fail), failing fast with a clear error. Production mode also disables the GraphQL playground and gRPC reflection. Any other value (or unset) is development mode.&lt;/td&gt;
					&lt;td&gt;unset (development)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;HTTP_MAX_BODY_BYTES&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Maximum request-body size (bytes) accepted on the HTTP app surface (GraphQL, REST, bulk upserts); oversized requests are rejected. Raise it if you bulk-import very large fleets.&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;8388608&lt;/code&gt; (8 MiB)&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote class='book-hint '&gt;
&lt;p&gt;In production, &lt;code&gt;DATABASE_URL&lt;/code&gt; should use &lt;code&gt;sslmode=verify-full&lt;/code&gt; against a secure
CockroachDB and a non-root, least-privilege SQL user — not the insecure local
default. Supply the cluster CA via &lt;code&gt;sslrootcert=&lt;/code&gt; in the URL or &lt;code&gt;DB_TLS_ROOT_CERT&lt;/code&gt;;
with &lt;code&gt;RACKATTACK_ENV=production&lt;/code&gt; the server refuses to boot on &lt;code&gt;sslmode=disable&lt;/code&gt;.&lt;/p&gt;</description></item><item><title>Security &amp; auth</title><link>https://lex00.github.io/rackattack/security/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://lex00.github.io/rackattack/security/</guid><description>&lt;h1 id="security--authentication"&gt;Security &amp;amp; authentication&lt;a class="anchor" href="#security--authentication"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;rackattack validates signed &lt;strong&gt;OIDC/JWT&lt;/strong&gt; bearer tokens at every transport edge
and gates the surface with &lt;strong&gt;role-based authorization&lt;/strong&gt; in the shared service
core — so the same rules apply whether a request arrives over gRPC, REST, or
GraphQL.&lt;/p&gt;
&lt;h2 id="how-it-works"&gt;How it works&lt;a class="anchor" href="#how-it-works"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Token validation at the edge.&lt;/strong&gt; A gRPC unary interceptor and an HTTP
middleware (covering both REST and GraphQL) validate the bearer token and
extract a principal.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Authorization in the core.&lt;/strong&gt; The principal flows into a shared &lt;code&gt;Authorizer&lt;/code&gt;
that gates the surface: &lt;strong&gt;reads are open to any authenticated principal&lt;/strong&gt;, while
&lt;strong&gt;mutations and bulk operations require a writer/admin role&lt;/strong&gt;. Because REST and
GraphQL call the service in-process, authorization lives in the wrapper they all
share — not only in the gRPC chain.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Both RS256/ES256 (via a JWKS endpoint) and HS256 (via a configured symmetric
secret) are supported.&lt;/p&gt;</description></item><item><title>Caching</title><link>https://lex00.github.io/rackattack/caching/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://lex00.github.io/rackattack/caching/</guid><description>&lt;h1 id="read-caching"&gt;Read caching&lt;a class="anchor" href="#read-caching"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Hot read RPCs — the screens plus device/rack lookups — are memoized by a
&lt;strong&gt;read-through cache&lt;/strong&gt; that wraps the service core. A cache hit skips the
recursive SQL &lt;em&gt;and&lt;/em&gt; the SVG render entirely.&lt;/p&gt;
&lt;h2 id="backends"&gt;Backends&lt;a class="anchor" href="#backends"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The cache is a seam with two interchangeable backends:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;In-process LRU&lt;/strong&gt; (default, single replica) — &lt;code&gt;CACHE_SIZE&lt;/code&gt; entries (default
&lt;code&gt;1024&lt;/code&gt;), expiring after &lt;code&gt;CACHE_TTL&lt;/code&gt; (default &lt;code&gt;30s&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Redis&lt;/strong&gt; (multi-replica) — set &lt;code&gt;REDIS_ADDR=host:6379&lt;/code&gt;. All replicas share one
cache, so an invalidation on any replica is seen by all.&lt;/li&gt;
&lt;/ul&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Env&lt;/th&gt;
					&lt;th&gt;Meaning&lt;/th&gt;
					&lt;th&gt;Default&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;CACHE_ENABLED&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;turn the read cache on/off&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;true&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;CACHE_TTL&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;entry time-to-live&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;30s&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;CACHE_SIZE&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;LRU capacity (entries)&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;1024&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;REDIS_ADDR&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;use Redis instead of the in-process LRU when set&lt;/td&gt;
					&lt;td&gt;—&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote class='book-hint '&gt;
&lt;p&gt;&lt;strong&gt;Run Redis when you run more than one replica.&lt;/strong&gt; The in-process LRU is
per-pod, so a mutation on pod A leaves pod B&amp;rsquo;s cache stale until the TTL
expires. A shared Redis gives global invalidation — set &lt;code&gt;REDIS_ADDR&lt;/code&gt; on every
replica. A single replica is fine on the LRU.&lt;/p&gt;</description></item><item><title>Audit &amp; CDC</title><link>https://lex00.github.io/rackattack/audit/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://lex00.github.io/rackattack/audit/</guid><description>&lt;h1 id="audit-logging--change-data-capture"&gt;Audit logging &amp;amp; change data capture&lt;a class="anchor" href="#audit-logging--change-data-capture"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Mutations are captured to an &lt;code&gt;audit_log&lt;/code&gt; table via CockroachDB
&lt;strong&gt;change-data-capture (CHANGEFEED)&lt;/strong&gt; and read back over HTTP. Tracked tables:
&lt;code&gt;devices&lt;/code&gt;, &lt;code&gt;racks&lt;/code&gt;, &lt;code&gt;crac_units&lt;/code&gt;, &lt;code&gt;cables&lt;/code&gt;, and &lt;code&gt;fabric_links&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="reading-the-history"&gt;Reading the history&lt;a class="anchor" href="#reading-the-history"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;serve&lt;/code&gt; exposes the change history on the HTTP port:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;curl -s &lt;span style="color:#e6db74"&gt;&amp;#39;localhost:8081/audit/history?table=racks&amp;amp;limit=50&amp;#39;&lt;/span&gt; | jq&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="two-delivery-paths-one-destination"&gt;Two delivery paths, one destination&lt;a class="anchor" href="#two-delivery-paths-one-destination"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Both paths land each change in &lt;code&gt;audit_log&lt;/code&gt;; pick one.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;In-process core changefeed&lt;/strong&gt; (default in k8s, license-free). Set
&lt;code&gt;AUDIT_CHANGEFEED=true&lt;/code&gt; and &lt;code&gt;serve&lt;/code&gt; runs an &lt;code&gt;EXPERIMENTAL CHANGEFEED&lt;/code&gt; over its
own connection, recording each change. No inbound network needed — ideal for
self-hosted/dev. &lt;strong&gt;Single-replica only:&lt;/strong&gt; this feed runs inside every replica,
so at more than one replica each mutation is recorded once per replica
(duplicate &lt;code&gt;audit_log&lt;/code&gt; rows). &lt;code&gt;serve&lt;/code&gt; warns about this at startup. Run it on
exactly one replica, or use the webhook sink below.&lt;/p&gt;</description></item><item><title>Fleet generator &amp; guided tour</title><link>https://lex00.github.io/rackattack/generator/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://lex00.github.io/rackattack/generator/</guid><description>&lt;h1 id="fleet-generator--guided-tour"&gt;Fleet generator &amp;amp; guided tour&lt;a class="anchor" href="#fleet-generator--guided-tour"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;More than a seeder: a &lt;strong&gt;self-driving guided tour&lt;/strong&gt;. A scale knob produces a
synthetic datacenter, then the tour mines its own interesting scenarios, writes
the prompts, runs them, and emits the diagrams — so any size of fleet produces its
own narrated walkthrough. Use it to evaluate rackattack against realistic sample
data before you wire in your own inventory.&lt;/p&gt;
&lt;figure class="diagram"&gt;
 &lt;img src="https://lex00.github.io/rackattack/diagrams/d6-example-pipeline.svg"
 alt="generate → mine → prompt → run → render" loading="lazy"&gt;&lt;figcaption&gt;&lt;em&gt;generate → mine → prompt → run → render&lt;/em&gt;&lt;/figcaption&gt;&lt;/figure&gt;

&lt;h2 id="generate-a-fleet-tunable-deterministic"&gt;Generate a fleet (tunable, deterministic)&lt;a class="anchor" href="#generate-a-fleet-tunable-deterministic"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;rackattack fleet new --sites &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt; --racks-per-row &lt;span style="color:#ae81ff"&gt;20&lt;/span&gt; --oversub 3:1 &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --redundancy ab --seed &lt;span style="color:#ae81ff"&gt;42&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;Scales from one rack → row → site → multi-site.&lt;/li&gt;
&lt;li&gt;Plausible topology: leaf-spine switching, structured cabling through patch
panels, A/B power, realistic device mixes and power/heat profiles.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Deterministic from &lt;code&gt;--seed&lt;/code&gt;&lt;/strong&gt; — same seed reproduces the same fleet. Benchmarks,
tests, and the example preset all depend on this.&lt;/li&gt;
&lt;li&gt;Plants guaranteed-interesting scenarios: a single-point-of-failure feed, an
over-budget thermal hotspot, a congested fabric uplink.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="run-the-guided-tour-mine--prompt--run--render"&gt;Run the guided tour (mine → prompt → run → render)&lt;a class="anchor" href="#run-the-guided-tour-mine--prompt--run--render"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;rackattack example run --preset example --out example-out&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Mine&lt;/strong&gt; — biggest-blast-radius feed, hottest rack, longest cable path,
most-congested link.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Prompt&lt;/strong&gt; — template natural-language questions around them (optionally
LLM-phrased for variety).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Run&lt;/strong&gt; — map each prompt to its tool call and execute.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Render&lt;/strong&gt; — emit the diagrams into a narrated gallery. At the example preset this
reproduces &lt;a href="https://github.com/lex00/rackattack/blob/main/NARRATIVE.md"&gt;&lt;code&gt;NARRATIVE.md&lt;/code&gt;&lt;/a&gt;
exactly.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In production the prompt → tool mapping is your own LLM agent over MCP; the
guided tour is a scripted stand-in that proves the pipeline without a live agent.&lt;/p&gt;</description></item><item><title>Performance &amp; scale</title><link>https://lex00.github.io/rackattack/performance/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://lex00.github.io/rackattack/performance/</guid><description>&lt;h1 id="performance--scale"&gt;Performance &amp;amp; scale&lt;a class="anchor" href="#performance--scale"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;The fleet generator exists so benchmarks are run against a &lt;em&gt;real&lt;/em&gt; synthetic
datacenter, not a toy. Full numbers, method, and reproduction steps are in
&lt;a href="https://github.com/lex00/rackattack/blob/main/BENCHMARKS.md"&gt;&lt;code&gt;BENCHMARKS.md&lt;/code&gt;&lt;/a&gt;;
this page is the orientation.&lt;/p&gt;
&lt;h2 id="hot-query-latency"&gt;Hot-query latency&lt;a class="anchor" href="#hot-query-latency"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;End-to-end latency of the three recursive/rollup queries, measured with
&lt;code&gt;hyperfine&lt;/code&gt; via the &lt;code&gt;rackattack query &amp;lt;screen&amp;gt;&lt;/code&gt; CLI (a full process →
connect → query round-trip, run &lt;a href="https://github.com/lex00/rackattack/blob/main/scripts/bench.sh"&gt;&lt;code&gt;scripts/bench.sh&lt;/code&gt;&lt;/a&gt;):&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Query&lt;/th&gt;
					&lt;th style="text-align: right"&gt;Mean&lt;/th&gt;
					&lt;th&gt;Notes&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;PowerBlastRadius&lt;/code&gt;&lt;/td&gt;
					&lt;td style="text-align: right"&gt;~193 ms&lt;/td&gt;
					&lt;td&gt;heaviest — recursive walk of the whole power chain&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;TraceCablePath&lt;/code&gt;&lt;/td&gt;
					&lt;td style="text-align: right"&gt;~28 ms&lt;/td&gt;
					&lt;td&gt;single port-graph path, ~constant in fleet size&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;ThermalHeadroom&lt;/code&gt;&lt;/td&gt;
					&lt;td style="text-align: right"&gt;~12 ms&lt;/td&gt;
					&lt;td&gt;grouped aggregate over one floor&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Reproduce on your own hardware with &lt;code&gt;just bench&lt;/code&gt;.&lt;/p&gt;</description></item><item><title>Deployment</title><link>https://lex00.github.io/rackattack/deployment/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://lex00.github.io/rackattack/deployment/</guid><description>&lt;h1 id="deployment"&gt;Deployment&lt;a class="anchor" href="#deployment"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;rackattack ships as a CGO-free static binary on &lt;code&gt;debian:bookworm-slim&lt;/code&gt; with
&lt;code&gt;graphviz&lt;/code&gt; installed (the blast-radius renderer shells out to &lt;code&gt;dot&lt;/code&gt;). The
Kubernetes manifests in
&lt;a href="https://github.com/lex00/rackattack/tree/main/deploy/k8s"&gt;&lt;code&gt;deploy/k8s/&lt;/code&gt;&lt;/a&gt; are a
kustomize base + overlay: &lt;code&gt;base/&lt;/code&gt; runs a single-node CockroachDB StatefulSet plus
the rackattack Deployment (dev/evaluation), and &lt;code&gt;production/&lt;/code&gt; layers secrets and
auth on top.&lt;/p&gt;
&lt;p&gt;The service is configured entirely through environment variables — see the
&lt;a href="../configuration/"&gt;Configuration reference&lt;/a&gt; for every setting and its default.&lt;/p&gt;
&lt;figure class="diagram"&gt;
 &lt;img src="https://lex00.github.io/rackattack/diagrams/d7-deployment.svg"
 alt="Kubernetes topology (validated locally on k3d)" loading="lazy"&gt;&lt;figcaption&gt;&lt;em&gt;Kubernetes topology (validated locally on k3d)&lt;/em&gt;&lt;/figcaption&gt;&lt;/figure&gt;

&lt;h2 id="whats-deployed"&gt;What&amp;rsquo;s deployed&lt;a class="anchor" href="#whats-deployed"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;StatefulSet &lt;code&gt;crdb&lt;/code&gt;&lt;/strong&gt; + a headless Service — CockroachDB running
&lt;code&gt;start-single-node --insecure&lt;/code&gt; (dev only).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Deployment &lt;code&gt;rackattack&lt;/code&gt;&lt;/strong&gt; — init containers create the database and apply
migrations before &lt;code&gt;serve&lt;/code&gt; starts; the Service exposes gRPC &lt;code&gt;:8080&lt;/code&gt; and REST
&lt;code&gt;:8081&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="local-validation-on-k3d"&gt;Local validation on k3d&lt;a class="anchor" href="#local-validation-on-k3d"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./scripts/k3d-up.sh &lt;span style="color:#75715e"&gt;# build image, create cluster, import image, apply, wait green&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./scripts/k3d-down.sh &lt;span style="color:#75715e"&gt;# delete the cluster&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;k3d-up.sh&lt;/code&gt; builds the image (if missing), creates the cluster, imports the local
image, &lt;code&gt;kubectl apply -k deploy/k8s/base&lt;/code&gt;, then waits on &lt;code&gt;rollout status&lt;/code&gt; for the
StatefulSet and Deployment. Reach the service with:&lt;/p&gt;</description></item><item><title>Minimal deployment</title><link>https://lex00.github.io/rackattack/minimal-deployment/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://lex00.github.io/rackattack/minimal-deployment/</guid><description>&lt;h1 id="minimal-deployment--single-host-docker-compose"&gt;Minimal deployment — single host (docker compose)&lt;a class="anchor" href="#minimal-deployment--single-host-docker-compose"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;The cheapest way to actually run rackattack: the whole stack on &lt;strong&gt;one host&lt;/strong&gt; via
&lt;code&gt;docker compose&lt;/code&gt; — the app, a secure single-node CockroachDB, and an edge TLS
proxy — with &lt;strong&gt;no Kubernetes, no operator, no managed database, no load balancer&lt;/strong&gt;.
It&amp;rsquo;s a real &lt;em&gt;secure small-prod&lt;/em&gt; posture for a homelab, colo, or small cloud, not a
throwaway.&lt;/p&gt;
&lt;p&gt;This is one of three deploy paths (see the &lt;a href="../deployment/"&gt;Deployment&lt;/a&gt; chooser).
The stack lives in
&lt;a href="https://github.com/lex00/rackattack/tree/main/deploy/compose"&gt;&lt;code&gt;deploy/compose/&lt;/code&gt;&lt;/a&gt;
and is authored in chant (TypeScript → &lt;code&gt;compose.yaml&lt;/code&gt;).&lt;/p&gt;</description></item><item><title>Observability</title><link>https://lex00.github.io/rackattack/observability/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://lex00.github.io/rackattack/observability/</guid><description>&lt;h1 id="observability"&gt;Observability&lt;a class="anchor" href="#observability"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;code&gt;serve&lt;/code&gt; is instrumented with &lt;strong&gt;Prometheus metrics&lt;/strong&gt; and &lt;strong&gt;OpenTelemetry traces&lt;/strong&gt;
end to end, so a request can be watched as RPC → query → render.&lt;/p&gt;
&lt;h2 id="metrics-prometheus"&gt;Metrics (Prometheus)&lt;a class="anchor" href="#metrics-prometheus"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Metrics are exposed at &lt;strong&gt;&lt;code&gt;/metrics&lt;/code&gt;&lt;/strong&gt; on the HTTP port. The endpoint is
&lt;strong&gt;unauthenticated&lt;/strong&gt; — it sits outside the auth middleware so scrapers reach it
without a token.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;curl -s localhost:8081/metrics | grep rackattack_&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;What&amp;rsquo;s exported:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Per-RPC rate / latency / error&lt;/strong&gt; — &lt;code&gt;rackattack_rpc_requests_total{method,code}&lt;/code&gt;,
&lt;code&gt;rackattack_rpc_duration_seconds&lt;/code&gt; (gRPC); plus
&lt;code&gt;rackattack_http_requests_total{route,status}&lt;/code&gt; for REST + GraphQL.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;DB pool saturation&lt;/strong&gt; — &lt;code&gt;rackattack_db_pool_{total,acquired,idle,max}_conns&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cache hit ratio&lt;/strong&gt; — &lt;code&gt;rackattack_cache_{hits,misses}_total&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Go runtime + process&lt;/strong&gt; collectors.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The k8s pod template carries &lt;code&gt;prometheus.io/{scrape,port,path}&lt;/code&gt; annotations for
annotation-based discovery (or use a &lt;code&gt;ServiceMonitor&lt;/code&gt; with the Prometheus
Operator).&lt;/p&gt;</description></item><item><title>Interaction model</title><link>https://lex00.github.io/rackattack/interaction/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://lex00.github.io/rackattack/interaction/</guid><description>&lt;h1 id="interaction-model"&gt;Interaction model&lt;a class="anchor" href="#interaction-model"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;The hover and select frames in
&lt;a href="https://github.com/lex00/rackattack/tree/main/assets"&gt;&lt;code&gt;assets/&lt;/code&gt;&lt;/a&gt; aren&amp;rsquo;t separate
renders — they&amp;rsquo;re &lt;strong&gt;states of one interactive artifact&lt;/strong&gt;. The interactive HTML
embeds the dataset, so hover is purely client-side (zero calls); only a click that
opens the inspector hydrates detail via &lt;code&gt;GetDevice&lt;/code&gt; / &lt;code&gt;GetPort&lt;/code&gt;.&lt;/p&gt;
&lt;figure class="diagram"&gt;
 &lt;img src="https://lex00.github.io/rackattack/diagrams/d8-interaction.svg"
 alt="Default → Hover → Select states and their call costs" loading="lazy"&gt;&lt;figcaption&gt;&lt;em&gt;Default → Hover → Select states and their call costs&lt;/em&gt;&lt;/figcaption&gt;&lt;/figure&gt;

&lt;h2 id="states"&gt;States&lt;a class="anchor" href="#states"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Default&lt;/strong&gt; — the full render.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hover (rollover)&lt;/strong&gt; — client-side highlight of the node under the pointer. No
server calls.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Select (click)&lt;/strong&gt; — opens the inspector for the clicked node, hydrated with a
&lt;code&gt;GetDevice&lt;/code&gt; or &lt;code&gt;GetPort&lt;/code&gt; call. As an operator clicks deeper, each click is one
more lookup.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="locked-conventions"&gt;Locked conventions&lt;a class="anchor" href="#locked-conventions"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The visual design system and interaction vocabulary are &lt;strong&gt;locked&lt;/strong&gt; in
&lt;a href="https://github.com/lex00/rackattack/blob/main/assets/DESIGN.md"&gt;&lt;code&gt;assets/DESIGN.md&lt;/code&gt;&lt;/a&gt;:
palette, typography, heat gradients, device icons, and the semantic highlight
rules (dead = red, survives = green). Renderers reproduce the approved mockups;
they don&amp;rsquo;t invent a new look. The interaction-cost model is detailed in
&lt;a href="https://github.com/lex00/rackattack/blob/main/TOOLS.md#interaction-model-what-hoverselect-cost"&gt;TOOLS.md&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Contributing</title><link>https://lex00.github.io/rackattack/contributing/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://lex00.github.io/rackattack/contributing/</guid><description>&lt;h1 id="contributing"&gt;Contributing&lt;a class="anchor" href="#contributing"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;h2 id="toolchain"&gt;Toolchain&lt;a class="anchor" href="#toolchain"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Go 1.25 · Docker · &lt;code&gt;protoc&lt;/code&gt; (+ &lt;code&gt;protoc-gen-go&lt;/code&gt;, &lt;code&gt;protoc-gen-go-grpc&lt;/code&gt;,
&lt;code&gt;protoc-gen-grpc-gateway&lt;/code&gt;) · &lt;code&gt;dot&lt;/code&gt; (Graphviz) · &lt;code&gt;rsvg-convert&lt;/code&gt; · &lt;code&gt;hugo&lt;/code&gt; (extended,
for these docs) · &lt;code&gt;just&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="local-setup"&gt;Local setup&lt;a class="anchor" href="#local-setup"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 1. start CockroachDB (single-node, insecure) for dev&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;just up &lt;span style="color:#75715e"&gt;# docker compose up&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 2. apply migrations and generate a fleet&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;rackattack migrate
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;rackattack fleet new --preset example
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 3. run the service (gRPC :8080, REST :8081)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;rackattack serve
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 4. ask a blast-radius question over REST&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;curl -s localhost:8081/rackattack.v1.Rackattack/PowerBlastRadius &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -d &lt;span style="color:#e6db74"&gt;&amp;#39;{&amp;#34;source_ref&amp;#34;:&amp;#34;feed:B-3&amp;#34;}&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Common &lt;code&gt;just&lt;/code&gt; recipes: &lt;code&gt;up&lt;/code&gt; / &lt;code&gt;down&lt;/code&gt; (CockroachDB), &lt;code&gt;bench&lt;/code&gt; (hyperfine on hot
queries), &lt;code&gt;image&lt;/code&gt; (container build), &lt;code&gt;k3d-up&lt;/code&gt; / &lt;code&gt;k3d-down&lt;/code&gt; (local cluster), and
the docs recipes below.&lt;/p&gt;</description></item></channel></rss>