<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Alex Artigues on lex00</title><link>https://lex00.github.io/</link><description>Recent content in Alex Artigues on lex00</description><generator>Hugo</generator><language>en-us</language><lastBuildDate>Fri, 28 Aug 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://lex00.github.io/index.xml" rel="self" type="application/rss+xml"/><item><title>A plan preview for k8s with ownership</title><link>https://lex00.github.io/posts/a-plan-preview-for-k8s-with-ownership/</link><pubDate>Fri, 28 Aug 2026 00:00:00 +0000</pubDate><guid>https://lex00.github.io/posts/a-plan-preview-for-k8s-with-ownership/</guid><description>&lt;p&gt;kubectl can already dry-run an apply against the real API server and show you what it would produce.&lt;/p&gt;
&lt;p&gt;&amp;ldquo;chant kube apply&amp;rdquo; and &amp;ldquo;chant kube delete&amp;rdquo; make that the default action instead of a flag you have to remember. Pass &lt;code&gt;--yes&lt;/code&gt; to persist.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://intentius.io/chant/"&gt;chant&lt;/a&gt;&amp;rsquo;s k8s client adds ownership knowledge on top of that.&lt;/p&gt;
&lt;h2 id="ownership-at-two-granularities"&gt;Ownership at two granularities&lt;/h2&gt;
&lt;p&gt;kubectl&amp;rsquo;s manager identity is generic, stamping whatever invoked it as the name on the field.&lt;/p&gt;</description></item><item><title>knr-ops beats Crossplane on the token bill</title><link>https://lex00.github.io/posts/knr-ops-beats-crossplane-on-tokens/</link><pubDate>Fri, 28 Aug 2026 00:00:00 +0000</pubDate><guid>https://lex00.github.io/posts/knr-ops-beats-crossplane-on-tokens/</guid><description>&lt;p&gt;Token savings in IaC is so hot right now.&lt;/p&gt;
&lt;p&gt;It pays to understand which tools save you the most money and why.&lt;/p&gt;
&lt;h2 id="knr-ops-beats-crossplane-where-the-work-happens"&gt;knr-ops beats Crossplane where the work happens&lt;/h2&gt;
&lt;p&gt;Here is a new round of &lt;a href="https://github.com/lex00/iac-cd-bench"&gt;iac-cd-bench&lt;/a&gt; with a result showing Crossplane losing on token spend to &lt;a href="https://github.com/polarsquad/knr-ops"&gt;knr-ops&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Haiku 4.5, k=3, all seven stacks, cold and warm, 252 runs.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://lex00.github.io/img/knr-ops-token-tasks.svg"
			alt="knr-ops versus Crossplane, average tokens per run by task. comprehend: knr-ops 5,076, Crossplane 6,431, knr-ops saves 21%. generate: knr-ops 9,010, Crossplane 9,836, saves 8%. modify: knr-ops 3,433, Crossplane 3,434, saves about 0%. debug: knr-ops 3,440, Crossplane 4,011, saves 14%."&gt;
&lt;/figure&gt;

&lt;p&gt;Crossplane does better on two task types, review and deep semantic questions. This is because Crossplane&amp;rsquo;s CRDs are cheaper than a Flux/kustomize overlay.&lt;/p&gt;</description></item><item><title>choudoufu cuts terralith optimization time in half</title><link>https://lex00.github.io/posts/choudoufu-cuts-terralith-optimization-time-in-half/</link><pubDate>Tue, 25 Aug 2026 00:00:00 +0000</pubDate><guid>https://lex00.github.io/posts/choudoufu-cuts-terralith-optimization-time-in-half/</guid><description>&lt;p&gt;&lt;a href="https://intentius.io/choudoufu/docs/"&gt;choudoufu&lt;/a&gt; is a fork of OpenTofu with &lt;a href="https://lex00.github.io/posts/tofu-tastes-better-with-identity-hooks/"&gt;identity hooks&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This blog takes a look at Cursor&amp;rsquo;s recent migration from Terraform to OpenTofu, and how it could have gone differently if it wasn&amp;rsquo;t held back by state.&lt;/p&gt;
&lt;h2 id="choudoufu-writes-ownership-on-the-resource-itself"&gt;choudoufu writes ownership on the resource itself&lt;/h2&gt;
&lt;p&gt;choudoufu adopts by stamping. Terraform adopts by fixing resolution in state.&lt;/p&gt;
&lt;p&gt;Two tags on the resource, read live at plan time. That&amp;rsquo;s the whole trick of &lt;a href="https://lex00.github.io/posts/tofu-tastes-better-with-identity-hooks/"&gt;identity hooks&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://lex00.github.io/img/cursor-migration/translation.svg" alt="The state world translated to the tag world"&gt;&lt;/p&gt;</description></item><item><title>Good tools can survive great "culture"</title><link>https://lex00.github.io/posts/good-tools-can-survive-great-culture/</link><pubDate>Sun, 23 Aug 2026 00:00:00 +0000</pubDate><guid>https://lex00.github.io/posts/good-tools-can-survive-great-culture/</guid><description>&lt;p&gt;Culture rots. It&amp;rsquo;s perfectly normal and to some degree not preventable.&lt;/p&gt;
&lt;p&gt;It rots because it&amp;rsquo;s an honor system, and honor systems are only as strong as the participants.&lt;/p&gt;
&lt;h2 id="above-the-clouds-of-responsibility"&gt;Above the clouds of responsibility&lt;/h2&gt;
&lt;p&gt;There is an invisible caste system in many orgs, and ops is at the bottom of it. The euphemism &amp;ldquo;Ops problem&amp;rdquo; has survived every re-org I&amp;rsquo;ve experienced.&lt;/p&gt;
&lt;p&gt;Watching the players at higher levels in the system feign ignorance about who will end up holding the bag can be maddening, because the answer is always the same. Ops.&lt;/p&gt;</description></item><item><title>Tofu tastes better with identity hooks</title><link>https://lex00.github.io/posts/tofu-tastes-better-with-identity-hooks/</link><pubDate>Sun, 23 Aug 2026 00:00:00 +0000</pubDate><guid>https://lex00.github.io/posts/tofu-tastes-better-with-identity-hooks/</guid><description>&lt;p&gt;Outside of k8s, infra tooling generally has pretty specific way of looking at ownership.&lt;/p&gt;
&lt;p&gt;They keep a ledger, and if a resource is in the ledger, the tool owns it. Simple.&lt;/p&gt;
&lt;p&gt;This simplicity feels so powerful, and it is, as long as you never get tasked with migration of the ledger across org boundaries.&lt;/p&gt;
&lt;h2 id="defining-ownership-in-aws"&gt;Defining ownership in AWS&lt;/h2&gt;
&lt;p&gt;choudoufu writes the answer onto the resource itself, as two tags.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;tofu-estate = prod-networking
tofu-address = aws_vpc.main
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;choudoufu treats these tags as hooks at plan time.&lt;/p&gt;</description></item><item><title>Terraform state has three pieces</title><link>https://lex00.github.io/posts/terraform-state-has-three-pieces/</link><pubDate>Wed, 19 Aug 2026 00:00:00 +0000</pubDate><guid>https://lex00.github.io/posts/terraform-state-has-three-pieces/</guid><description>&lt;p&gt;A state file does three jobs.&lt;/p&gt;
&lt;p&gt;It says which live resource an address refers to. It holds values the cloud has nowhere to put. And it records that an effect happened.&lt;/p&gt;
&lt;p&gt;Those got bundled because one file happened to do all of them. Bundling is what turns persistence into a permission boundary, a secret, and a thing to lock.&lt;/p&gt;
&lt;p&gt;Take them apart and each goes somewhere AWS already has. Identity becomes two tags on the resource. Values go in a record store. Effects get a receipt you declare, so the plan shows the migration coming before anything fires.&lt;/p&gt;</description></item><item><title>A billion proofs a day</title><link>https://lex00.github.io/posts/a-billion-proofs-a-day/</link><pubDate>Sat, 15 Aug 2026 00:00:00 +0000</pubDate><guid>https://lex00.github.io/posts/a-billion-proofs-a-day/</guid><description>&lt;p&gt;Amazon&amp;rsquo;s Automated Reasoning Group just published &lt;a href="https://www.amazon.science/blog/a-decade-of-mathematical-certainty-reflections-on-the-automated-reasoning-group"&gt;a decade of reflections&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s the story of a decade spent proving AWS correct. Their policy engine Zelkova answers &lt;a href="https://www.amazon.science/blog/a-billion-smt-queries-a-day"&gt;a billion SMT queries a day&lt;/a&gt; about what policies permit. Every one of these queries happens after the artifact exists. The queries are against normal JSON that nothing upstream cleans up or constrains.&lt;/p&gt;
&lt;p&gt;CDK has a miniature version of this. It runs a risky statement merge at synth, so a machine-checked &lt;a href="https://github.com/aws/aws-cdk/blob/main/packages/aws-cdk-lib/aws-iam/docs/policy-merging.als"&gt;Alloy model&lt;/a&gt; in the repo proves the merge algorithm safe in advance.&lt;/p&gt;</description></item><item><title>Anthropic reached the same list</title><link>https://lex00.github.io/posts/anthropic-reached-the-same-list/</link><pubDate>Fri, 14 Aug 2026 00:00:00 +0000</pubDate><guid>https://lex00.github.io/posts/anthropic-reached-the-same-list/</guid><description>&lt;p&gt;Anthropic published &lt;a href="https://claude.com/blog/how-anthropic-secures-its-ai-native-software-development-lifecycle"&gt;how they secure an AI-native software development lifecycle&lt;/a&gt;. Claude writes roughly 80% of the code merged there, so no control that depends on a human reading everything survives.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://accessibleops.net"&gt;Accessible Ops&lt;/a&gt; is fourteen principles for infrastructure operations, written for the same pressure from the other end. Most of what Anthropic describes lands on rows in that list.&lt;/p&gt;
&lt;p&gt;Their governing rule, the Principle of Least Agency, draws hard boundaries around what an agent can access and do rather than relying on what it is told. chant is partway there. &lt;code&gt;chant build&lt;/code&gt; imports your TypeScript and runs it, held safe only by lint rules. &lt;code&gt;chant build --fold&lt;/code&gt; reduces the source to a value without executing the module, and &lt;code&gt;--sandbox&lt;/code&gt; confines whatever falls back. Anthropic&amp;rsquo;s rule is a good argument for making fold the default.&lt;/p&gt;</description></item><item><title>Take a whiff of choudoufu</title><link>https://lex00.github.io/posts/take-a-whiff-of-choudoufu/</link><pubDate>Fri, 14 Aug 2026 00:00:00 +0000</pubDate><guid>https://lex00.github.io/posts/take-a-whiff-of-choudoufu/</guid><description>&lt;p&gt;Choudoufu is IAM-governed state for OpenTofu. Estates are inherited by granting access.&lt;/p&gt;
&lt;p&gt;Terraform bundles three jobs into a state model that has survived for too long. Ownership, estate boundaries, and effect memory all live in the same artifact, behind the same lock, at the same access level.&lt;/p&gt;
&lt;p&gt;This is an extremely convenient workflow for the folks who get to drive it. It can also make life terribly difficult for operators who are blessed with inheriting the estate as teams are &amp;ldquo;restructured&amp;rdquo;. Orgs who share a single production account across many teams see the worst of this.&lt;/p&gt;</description></item><item><title>Guardrails that survive the round trip</title><link>https://lex00.github.io/posts/guardrails-that-survive-the-round-trip/</link><pubDate>Mon, 10 Aug 2026 00:00:00 +0000</pubDate><guid>https://lex00.github.io/posts/guardrails-that-survive-the-round-trip/</guid><description>&lt;figure class="diagram" role="img" aria-label="Bird&amp;#39;s eye view of a road curving hard through the frame. Along the outside of the curve runs a cliff edge drawn with hachure ticks, black void beyond it. A big rig labelled chant on its trailer rounds the upper curve tightly in the inner lane. A guardrail lines the cliff side, intact below the bend and intact beyond it, but torn open at the apex: gray rail fragments twist outward and skid marks point at the gap, where a big rig with CLICKOPS on its trailer is jackknifing mid-air past the edge, over the void."&gt;
&lt;svg xmlns="http://www.w3.org/2000/svg" viewBox="70 10 810 350" font-family="-apple-system, Segoe UI, Helvetica, Arial, sans-serif"&gt;
 &lt;rect x="70" y="10" width="810" height="350" fill="#0d1117"/&gt;

 &lt;!-- the drop: everything left and above the cliff edge --&gt;
 &lt;path d="M0,490 L300,490 C315,390 335,315 368,240 C404,158 462,112 525,72 C588,32 690,28 790,22 L880,20 L880,0 L0,0 Z" fill="#04070b"/&gt;
 &lt;path d="M300,490 C315,390 335,315 368,240 C404,158 462,112 525,72 C588,32 690,28 790,22 L880,20" fill="none" stroke="#3d4551" stroke-width="2.6"/&gt;
 &lt;path d="M290,490 C305,390 325,315 358,238 C394,156 452,108 515,68 C578,28 686,22 786,16 L880,14" fill="none" stroke="#262d36" stroke-width="3.4" opacity="0.7"/&gt;
 &lt;path d="M278,490 C293,390 313,313 346,236 C382,154 440,104 503,64 C566,24 682,16 782,10 L880,8" fill="none" stroke="#1a2029" stroke-width="4.5" opacity="0.5"/&gt;

 &lt;!-- terraces far below, falling away from the cliff --&gt;
 &lt;g fill="none" stroke="#0e141c" stroke-width="2"&gt;
 &lt;path d="M170,470 C190,360 215,255 265,160 C297,98 320,55 335,10"/&gt;
 &lt;path d="M95,470 C115,365 140,265 190,175 C222,113 248,68 265,20"/&gt;
 &lt;/g&gt;

 &lt;!-- cliff hachures, ticking into the void --&gt;
 &lt;g stroke="#3d4551" stroke-width="1.6"&gt;
 &lt;line x1="308" y1="440" x2="290" y2="436"/&gt;
 &lt;line x1="318" y1="392" x2="300" y2="387"/&gt;
 &lt;line x1="328" y1="345" x2="310" y2="339"/&gt;
 &lt;line x1="342" y1="298" x2="324" y2="291"/&gt;
 &lt;line x1="360" y1="253" x2="342" y2="245"/&gt;
 &lt;line x1="382" y1="209" x2="364" y2="199"/&gt;
 &lt;line x1="410" y1="168" x2="393" y2="156"/&gt;
 &lt;line x1="444" y1="131" x2="428" y2="118"/&gt;
 &lt;line x1="484" y1="98" x2="470" y2="84"/&gt;
 &lt;line x1="530" y1="70" x2="519" y2="54"/&gt;
 &lt;line x1="584" y1="47" x2="576" y2="30"/&gt;
 &lt;line x1="646" y1="34" x2="641" y2="16"/&gt;
 &lt;line x1="712" y1="27" x2="709" y2="9"/&gt;
 &lt;line x1="782" y1="23" x2="780" y2="5"/&gt;
 &lt;/g&gt;

 &lt;!-- the road, bending through the frame --&gt;
 &lt;path d="M424,490 C434,390 446,325 484,252 C524,176 606,136 700,118 C770,105 820,102 890,102" fill="none" stroke="#1e242c" stroke-width="92"/&gt;
 &lt;path d="M424,490 C434,390 446,325 484,252 C524,176 606,136 700,118 C770,105 820,102 890,102" fill="none" stroke="#8b949e" stroke-width="3" stroke-dasharray="20 16"/&gt;

 &lt;!-- skid marks toward the breach --&gt;
 &lt;g stroke="#0c1015" stroke-width="7" fill="none" stroke-linecap="round"&gt;
 &lt;path d="M468,306 C460,272 448,242 428,212"/&gt;
 &lt;path d="M488,312 C480,278 468,246 448,216"/&gt;
 &lt;/g&gt;

 &lt;!-- guardrail, cliff side: whole below, whole beyond, torn open at the apex --&gt;
 &lt;g stroke="#a89878" stroke-width="4" fill="none"&gt;
 &lt;path d="M366,486 C376,396 386,338 410,274"/&gt;
 &lt;path d="M508,138 C548,110 596,90 650,77 C722,60 790,54 880,52"/&gt;
 &lt;/g&gt;
 &lt;g fill="#a89878"&gt;
 &lt;circle cx="369" cy="458" r="3.2"/&gt;
 &lt;circle cx="373" cy="424" r="3.2"/&gt;
 &lt;circle cx="378" cy="390" r="3.2"/&gt;
 &lt;circle cx="385" cy="356" r="3.2"/&gt;
 &lt;circle cx="394" cy="320" r="3.2"/&gt;
 &lt;circle cx="402" cy="296" r="3.2"/&gt;
 &lt;circle cx="410" cy="274" r="3.2"/&gt;
 &lt;circle cx="508" cy="138" r="3.2"/&gt;
 &lt;circle cx="536" cy="118" r="3.2"/&gt;
 &lt;circle cx="568" cy="100" r="3.2"/&gt;
 &lt;circle cx="604" cy="87" r="3.2"/&gt;
 &lt;circle cx="650" cy="77" r="3.2"/&gt;
 &lt;circle cx="700" cy="66" r="3.2"/&gt;
 &lt;circle cx="756" cy="58" r="3.2"/&gt;
 &lt;circle cx="820" cy="53" r="3.2"/&gt;
 &lt;/g&gt;

 &lt;!-- the breach: torn pieces, one gone over the edge --&gt;
 &lt;g stroke="#8b949e" stroke-width="4" fill="none" stroke-linecap="round"&gt;
 &lt;path d="M418,252 L446,220" transform="rotate(-30 432 236)"/&gt;
 &lt;path d="M462,196 L492,166" transform="rotate(26 477 181)"/&gt;
 &lt;/g&gt;
 &lt;path d="M386,190 L412,168" stroke="#6b5f49" stroke-width="4" fill="none" stroke-linecap="round" transform="rotate(-50 399 179)"/&gt;
 &lt;g fill="#8b949e"&gt;
 &lt;circle cx="424" cy="244" r="3"/&gt;
 &lt;circle cx="484" cy="174" r="3"/&gt;
 &lt;circle cx="392" cy="184" r="3"/&gt;
 &lt;/g&gt;

 &lt;!-- the chant rig, tracking the curve in the inner lane --&gt;
 &lt;g transform="translate(667,158) rotate(-11)" fill="#000000" opacity="0.3"&gt;
 &lt;rect x="-48" y="-11" width="64" height="22" rx="2.5"/&gt;
 &lt;rect x="20" y="-10" width="20" height="20" rx="3" transform="rotate(10 26 0)"/&gt;
 &lt;/g&gt;
 &lt;g transform="translate(662,150) rotate(-11)"&gt;
 &lt;rect x="-48" y="-7.5" width="64" height="22" rx="2.5" fill="#1b2129"/&gt;
 &lt;rect x="20" y="-6.5" width="20" height="20" rx="3" fill="#1b2129" transform="rotate(10 26 0)"/&gt;
 &lt;rect x="-48" y="-11" width="64" height="22" rx="2.5" fill="#2d333b" stroke="#57606a" stroke-width="1.4"/&gt;
 &lt;g transform="rotate(10 26 0)"&gt;
 &lt;rect x="20" y="-10" width="20" height="20" rx="3" fill="#2d333b" stroke="#57606a" stroke-width="1.4"/&gt;
 &lt;line x1="34" y1="-8" x2="34" y2="8" stroke="#57606a" stroke-width="1.2"/&gt;
 &lt;/g&gt;
 &lt;text x="-16" y="4" text-anchor="middle" font-size="11" font-weight="700" letter-spacing="1" fill="#7ee787"&gt;chant&lt;/text&gt;
 &lt;/g&gt;

 &lt;!-- the big rig, straight on where the road wasn't, jackknifing through the rail --&gt;
 &lt;g transform="translate(369,143) rotate(-112)" fill="#000000" opacity="0.3"&gt;
 &lt;rect x="-48" y="-11" width="64" height="22" rx="2.5"/&gt;
 &lt;rect x="20" y="-10" width="20" height="20" rx="3" transform="rotate(20 26 0)"/&gt;
 &lt;/g&gt;
 &lt;g transform="translate(362,132) rotate(-112)"&gt;
 &lt;rect x="-48" y="-7.5" width="64" height="22" rx="2.5" fill="#1b2129"/&gt;
 &lt;rect x="20" y="-6.5" width="20" height="20" rx="3" fill="#1b2129" transform="rotate(20 26 0)"/&gt;
 &lt;rect x="-48" y="-11" width="64" height="22" rx="2.5" fill="#3d4551" stroke="#8b949e" stroke-width="1.4"/&gt;
 &lt;g transform="rotate(20 26 0)"&gt;
 &lt;rect x="20" y="-10" width="20" height="20" rx="3" fill="#3d4551" stroke="#8b949e" stroke-width="1.4"/&gt;
 &lt;line x1="34" y1="-8" x2="34" y2="8" stroke="#8b949e" stroke-width="1.2"/&gt;
 &lt;/g&gt;
 &lt;text x="-16" y="3.5" text-anchor="middle" font-size="9" font-weight="700" letter-spacing="0.4" fill="#e6edf3" transform="rotate(180 -16 0)"&gt;CLICKOPS&lt;/text&gt;
 &lt;/g&gt;
 &lt;g stroke="#30363d" stroke-width="2" fill="none" stroke-linecap="round" opacity="0.8"&gt;
 &lt;path d="M418,208 C408,196 400,186 394,176"/&gt;
 &lt;path d="M436,196 C426,184 418,174 412,164"/&gt;
 &lt;/g&gt;

 &lt;!-- the part where it goes badly --&gt;
 &lt;text x="437" y="222" font-size="26" text-anchor="middle"&gt;💥&lt;/text&gt;
 &lt;text x="404" y="184" font-size="15" text-anchor="middle"&gt;🔥&lt;/text&gt;
 &lt;text x="384" y="158" font-size="12" text-anchor="middle"&gt;🔥&lt;/text&gt;
 &lt;text x="352" y="112" font-size="13" text-anchor="middle"&gt;🔥&lt;/text&gt;

 &lt;!-- the driver, electing a different outcome --&gt;
 &lt;g transform="translate(396,118) rotate(-35)" stroke="#8b949e" stroke-width="2" fill="none" stroke-linecap="round"&gt;
 &lt;circle cx="0" cy="-7.5" r="2.8" fill="#8b949e" stroke="none"/&gt;
 &lt;line x1="0" y1="-4.5" x2="0" y2="4"/&gt;
 &lt;path d="M0,-2 L-5.5,-6.5"/&gt;
 &lt;path d="M0,-2 L5.5,-7.5"/&gt;
 &lt;path d="M0,4 L-5.5,9.5"/&gt;
 &lt;path d="M0,4 L5.5,8"/&gt;
 &lt;/g&gt;
 &lt;g stroke="#57606a" stroke-width="1.4" fill="none" stroke-linecap="round" opacity="0.7"&gt;
 &lt;path d="M378,124 C372,120 367,115 363,109"/&gt;
 &lt;path d="M382,133 C376,129 371,124 367,118"/&gt;
 &lt;/g&gt;
&lt;/svg&gt;

&lt;/figure&gt;
&lt;p&gt;Kubectl and its cousins operate on your estate based on domain knowledge they carry.&lt;/p&gt;</description></item><item><title>The revolving door of authoritative state</title><link>https://lex00.github.io/posts/the-revolving-door-of-authoritative-state/</link><pubDate>Tue, 04 Aug 2026 00:00:00 +0000</pubDate><guid>https://lex00.github.io/posts/the-revolving-door-of-authoritative-state/</guid><description>&lt;p&gt;Pulumi, an infra company founded on TypeScript, is now shipping HCL.&lt;/p&gt;
&lt;p&gt;Every argument Pulumi opened with has been repackaged as a feature.&lt;/p&gt;
&lt;p&gt;This pivot gave me whiplash reading it today. Imagine moving out of one authoritative state prison into another.&lt;/p&gt;
&lt;p&gt;I build chant, an infra compiler. You write TypeScript, it compiles to CloudFormation or Kubernetes YAML, and nothing runs.&lt;/p&gt;
&lt;h1 id="typescript-as-data-was-pulumis-to-have"&gt;TypeScript as Data was Pulumi&amp;rsquo;s to have&lt;/h1&gt;
&lt;p&gt;Luke Hoban co-created TypeScript and then brought it to infrastructure.&lt;/p&gt;</description></item><item><title>An ecosystem of gruel</title><link>https://lex00.github.io/posts/an-ecosystem-of-gruel/</link><pubDate>Mon, 03 Aug 2026 00:00:00 +0000</pubDate><guid>https://lex00.github.io/posts/an-ecosystem-of-gruel/</guid><description>&lt;p&gt;Configuration tooling keeps getting thrown into one cauldron. Start with eye of newt, then add a splash of versioning, a pinch of transformation, and a few sprigs of authoritative state.&lt;/p&gt;
&lt;p&gt;Gruel ends up tasting the same no matter how it gets started. Once cooked you have no way to cleanly extract any of the ingredients.&lt;/p&gt;
&lt;figure class="diagram" role="img" aria-label="A bowl of gruel seen front on, steaming, with a few flies circling. Lumps break the surface, three of them labelled with pairs that got cooked together: state plus ownership, authoring plus delivery, index plus authority."&gt;
&lt;svg xmlns="http://www.w3.org/2000/svg" viewBox="-70 0 640 320" style="max-width:470px;display:block;margin:0 auto" font-family="-apple-system, Segoe UI, Helvetica, Arial, sans-serif"&gt;
 &lt;rect x="-70" y="0" width="640" height="320" fill="#0d1117"/&gt;

 &lt;!-- stink lines --&gt;
 &lt;g fill="none" stroke="#6e7681" stroke-width="2" stroke-linecap="round" opacity="0.3"&gt;
 &lt;path d="M126,126 C110,110 142,98 126,82 C116,72 132,60 126,48"/&gt;
 &lt;path d="M182,120 C166,102 198,90 182,72 C172,60 188,48 182,34"/&gt;
 &lt;path d="M246,116 C228,96 262,82 244,62 C234,50 250,36 244,20"/&gt;
 &lt;path d="M310,120 C294,102 326,90 310,72 C300,60 316,48 310,34"/&gt;
 &lt;path d="M364,126 C348,110 380,98 364,82 C354,72 370,60 364,48"/&gt;
 &lt;/g&gt;

 &lt;!-- flies, seen from above --&gt;
 &lt;defs&gt;
 &lt;g id="fly"&gt;
 &lt;ellipse cx="-4.8" cy="0.4" rx="5.4" ry="2.1" transform="rotate(-30 -4.8 0.4)" fill="#8b949e" opacity="0.4"/&gt;
 &lt;ellipse cx="4.8" cy="0.4" rx="5.4" ry="2.1" transform="rotate(30 4.8 0.4)" fill="#8b949e" opacity="0.4"/&gt;
 &lt;g stroke="#8b949e" stroke-width="0.75" stroke-linecap="round" opacity="0.8" fill="none"&gt;
 &lt;path d="M-2,-2.4 L-5.6,-4.6"/&gt;&lt;path d="M-2.2,0 L-6.2,0.6"/&gt;&lt;path d="M-2,2.2 L-5.2,4.6"/&gt;
 &lt;path d="M2,-2.4 L5.6,-4.6"/&gt;&lt;path d="M2.2,0 L6.2,0.6"/&gt;&lt;path d="M2,2.2 L5.2,4.6"/&gt;
 &lt;/g&gt;
 &lt;ellipse cx="0" cy="3.5" rx="2.3" ry="4" fill="#8b949e"/&gt;
 &lt;ellipse cx="0" cy="-1.6" rx="2.7" ry="2.9" fill="#8b949e"/&gt;
 &lt;ellipse cx="0" cy="-5.5" rx="2.6" ry="2.1" fill="#8b949e"/&gt;
 &lt;circle cx="-1.5" cy="-6.1" r="1.15" fill="#0d1117" opacity="0.9"/&gt;
 &lt;circle cx="1.5" cy="-6.1" r="1.15" fill="#0d1117" opacity="0.9"/&gt;
 &lt;/g&gt;
 &lt;/defs&gt;

 &lt;use href="#fly" transform="translate(150 56) rotate(24) scale(0.95)" opacity="0.9"/&gt;
 &lt;use href="#fly" transform="translate(291 37) rotate(-38) scale(0.75)" opacity="0.8"/&gt;
 &lt;use href="#fly" transform="translate(398 73) rotate(118) scale(0.82)" opacity="0.75"/&gt;
 &lt;g fill="none" stroke="#8b949e" stroke-width="1" stroke-dasharray="2 4" stroke-linecap="round" opacity="0.4"&gt;
 &lt;path d="M132,70 C142,62 156,68 168,58"/&gt;
 &lt;path d="M382,86 C392,80 402,84 414,76"/&gt;
 &lt;/g&gt;

 &lt;!-- labels --&gt;
 &lt;g font-size="12" font-weight="600" fill="#c9bfa6" text-anchor="middle"&gt;
 &lt;text x="120" y="114"&gt;state + ownership&lt;/text&gt;
 &lt;text x="248" y="94"&gt;authoring + delivery&lt;/text&gt;
 &lt;text x="366" y="112"&gt;index + authority&lt;/text&gt;
 &lt;/g&gt;

 &lt;!-- bowl body --&gt;
 &lt;path d="M75,150 C75,230 155,262 250,262 C345,262 425,230 425,150 Z" fill="#1c2128" stroke="#484f58" stroke-width="3"/&gt;
 &lt;path d="M99,196 C110,232 158,254 208,260" fill="none" stroke="#6e7681" stroke-width="2.5" opacity="0.25" stroke-linecap="round"/&gt;

 &lt;!-- gruel surface --&gt;
 &lt;ellipse cx="250" cy="150" rx="175" ry="30" fill="#4a4636" stroke="#5f5942" stroke-width="3"/&gt;
 &lt;ellipse cx="200" cy="143" rx="40" ry="8" fill="#565040" opacity="0.5"/&gt;
 &lt;ellipse cx="314" cy="161" rx="48" ry="9" fill="#3f3c2e" opacity="0.5"/&gt;

 &lt;!-- domes breaking the surface --&gt;
 &lt;path d="M108,149 a25,13 0 0 1 50,0 z" fill="#6b5f49" stroke="#877a5f" stroke-width="1.6"/&gt;
 &lt;ellipse cx="124" cy="142" rx="7" ry="3" fill="#8a7c60" opacity="0.55"/&gt;

 &lt;path d="M212,158 a36,19 0 0 1 72,0 z" fill="#6b5f49" stroke="#877a5f" stroke-width="1.6"/&gt;
 &lt;ellipse cx="234" cy="147" rx="10" ry="4" fill="#8a7c60" opacity="0.55"/&gt;

 &lt;path d="M336,147 a24,13 0 0 1 48,0 z" fill="#6b5f49" stroke="#877a5f" stroke-width="1.6"/&gt;
 &lt;ellipse cx="350" cy="141" rx="6.5" ry="2.8" fill="#8a7c60" opacity="0.55"/&gt;

 &lt;!-- unlabelled lumps --&gt;
 &lt;path d="M172,171 a17,8 0 0 1 34,0 z" fill="#5e5442" stroke="#877a5f" stroke-width="1.4"/&gt;
 &lt;path d="M292,137 a14,6 0 0 1 28,0 z" fill="#5e5442" stroke="#877a5f" stroke-width="1.4"/&gt;
 &lt;path d="M372,167 a15,7 0 0 1 30,0 z" fill="#5e5442" stroke="#877a5f" stroke-width="1.4"/&gt;
 &lt;path d="M92,164 a13,6 0 0 1 26,0 z" fill="#5e5442" stroke="#877a5f" stroke-width="1.4"/&gt;

 &lt;!-- foot --&gt;
 &lt;ellipse cx="250" cy="266" rx="58" ry="10" fill="#161b22" stroke="#484f58" stroke-width="3"/&gt;

&lt;/svg&gt;

&lt;/figure&gt;
&lt;p&gt;Clean separation of concerns with toolchains like this boils down to the fact that you get to drink yours from one bowl. This sounds pretty convenient at first. If you like your food served this way then everything is fine.&lt;/p&gt;</description></item><item><title>aws-bench: scenario 1 wrap</title><link>https://lex00.github.io/posts/aws-bench-scenario-1-wrap/</link><pubDate>Fri, 31 Jul 2026 00:00:00 +0000</pubDate><guid>https://lex00.github.io/posts/aws-bench-scenario-1-wrap/</guid><description>&lt;p&gt;Scenario 1 is done. aws-bench puts an agent in front of a live AWS estate and grades its answers.&lt;/p&gt;
&lt;p&gt;Six configurations ran it on the same model, Haiku 4.5: chant, Pulumi, Terraform, AWS CDK, Alchemy, and an agent holding nothing but the AWS CLI. Eight questions, three attempts each, 24 trials apiece, against six EC2 instances spread over three regions.&lt;/p&gt;
&lt;h2 id="the-results-live-on-chant-bench"&gt;The results live on chant-bench&lt;/h2&gt;
&lt;p&gt;I used to keep a post per matchup. That stopped working the first time I re-ran the benchmark and half the numbers moved, so the results now live where they are generated.&lt;/p&gt;</description></item><item><title>Queryable Infrastructure</title><link>https://lex00.github.io/posts/queryable-infrastructure/</link><pubDate>Tue, 28 Jul 2026 00:00:00 +0000</pubDate><guid>https://lex00.github.io/posts/queryable-infrastructure/</guid><description>&lt;p&gt;Agentic ops means agents need to query your infra on demand. If the live details of your estate are fragmented this can lead to extra lookups costing time and tokens.&lt;/p&gt;
&lt;p&gt;I measured this on &lt;a href="https://lex00.github.io/posts/aws-bench-scenario-1-wrap/"&gt;aws-bench&lt;/a&gt;: asked which security groups were attached to nothing, every toolchain that reads a stored copy of the estate scored 0 out of 3.&lt;/p&gt;
&lt;p&gt;Many things can be queried like a database without being one. The live cloud is one of them.&lt;/p&gt;</description></item><item><title>Flame graphing the leftness of infra tooling</title><link>https://lex00.github.io/posts/flame-graphing-the-leftness-of-infra-tooling/</link><pubDate>Mon, 27 Jul 2026 00:00:00 +0000</pubDate><guid>https://lex00.github.io/posts/flame-graphing-the-leftness-of-infra-tooling/</guid><description>&lt;p&gt;Last month I claimed &lt;a href="https://intentius.io/chant/"&gt;chant&lt;/a&gt; sits to the left of other infra toolchains when it comes to execution.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://lex00.github.io/img/leftness-cartoon.svg"
			alt="Two bars. cdk synth: your code and its infrastructure library execute from almost the start until the plan exists. chant build: the tool reads your files like a recipe without cooking it, and your code never runs."&gt;
&lt;/figure&gt;

&lt;p&gt;To prove this claim, I wrote the same small app for both CDK and chant. Next, I verified both produce the same resources, and ran each tool with Node&amp;rsquo;s profiler recording.&lt;/p&gt;</description></item><item><title>TypeScript is the right choice for infra</title><link>https://lex00.github.io/posts/typescript-is-the-right-choice-for-infra/</link><pubDate>Sun, 26 Jul 2026 00:00:00 +0000</pubDate><guid>https://lex00.github.io/posts/typescript-is-the-right-choice-for-infra/</guid><description>&lt;p&gt;Typed configuration languages are one fix for YAML hell. &lt;a href="https://pkl-lang.org/"&gt;Pkl&lt;/a&gt;, &lt;a href="https://cuelang.org/"&gt;CUE&lt;/a&gt;, and &lt;a href="https://kcl-lang.io/"&gt;KCL&lt;/a&gt; give you types, value constraints, and a compiler.&lt;/p&gt;
&lt;p&gt;TypeScript solves the same problem, but it keeps going. It is the ideal foundation for an infrastructure toolchain, and chant is the proof.&lt;/p&gt;
&lt;h2 id="the-config-languages-take-wheelers-deal"&gt;The config languages take Wheeler&amp;rsquo;s deal&lt;/h2&gt;
&lt;p&gt;David Wheeler&amp;rsquo;s &lt;a href="https://en.wikipedia.org/wiki/Fundamental_theorem_of_software_engineering"&gt;line&lt;/a&gt; is that any problem in computer science can be solved by adding another level of indirection. Kevlin Henney&amp;rsquo;s addendum is that this fails on the problem of too many levels of indirection.&lt;/p&gt;</description></item><item><title>The long tail is a tail</title><link>https://lex00.github.io/posts/the-long-tail-is-a-tail/</link><pubDate>Sat, 25 Jul 2026 00:00:00 +0000</pubDate><guid>https://lex00.github.io/posts/the-long-tail-is-a-tail/</guid><description>&lt;p&gt;By definition a tail is the small, infrequent remainder. The long tail of spec-less APIs never touches chant. Here&amp;rsquo;s why.&lt;/p&gt;
&lt;p&gt;chant compiles a typed source to the platform&amp;rsquo;s native spec, while some platforms are a pure API with nothing declarative underneath.&lt;/p&gt;
&lt;figure class="diagram" role="img" aria-label="A golden spiral. The specced platforms, AWS, Kubernetes, the clouds, CI, are the wide outer sweep, and the long tail tapers to a point at the center."&gt;
&lt;svg xmlns="http://www.w3.org/2000/svg" width="1520" height="1000" viewBox="0 0 1520 1000" font-family="Helvetica Neue, Helvetica, Arial, sans-serif"&gt;
&lt;defs&gt;
&lt;radialGradient id="g" cx="0.46" cy="0.47" r="0.62"&gt;&lt;stop offset="0" stop-color="#6c8cff" stop-opacity="0.15"/&gt;&lt;stop offset="0.72" stop-color="#6c8cff" stop-opacity="0"/&gt;&lt;/radialGradient&gt;
&lt;linearGradient id="rib" x1="0.1" y1="0" x2="0.9" y2="1"&gt;&lt;stop offset="0" stop-color="#8fa8ff"/&gt;&lt;stop offset="1" stop-color="#5673e6"/&gt;&lt;/linearGradient&gt;
&lt;/defs&gt;
&lt;rect width="1520" height="1000" fill="#0f1117"/&gt;
&lt;rect width="1520" height="1000" fill="url(#g)"/&gt;
&lt;path d="M 838.0 142.5 L 829.3 142.6 L 820.7 143.0 L 812.1 143.5 L 803.6 144.2 L 795.1 145.1 L 786.7 146.1 L 778.4 147.3 L 770.2 148.6 L 762.0 150.1 L 754.0 151.8 L 746.0 153.5 L 738.1 155.5 L 730.3 157.6 L 722.5 159.8 L 714.9 162.2 L 707.4 164.7 L 699.9 167.3 L 692.6 170.1 L 685.3 172.9 L 678.2 176.0 L 671.1 179.1 L 664.2 182.4 L 657.4 185.7 L 650.7 189.2 L 644.1 192.8 L 637.6 196.5 L 631.2 200.3 L 625.0 204.3 L 618.8 208.3 L 612.8 212.4 L 606.9 216.6 L 601.1 220.9 L 595.4 225.3 L 589.9 229.7 L 584.5 234.3 L 579.2 238.9 L 574.0 243.6 L 568.9 248.4 L 564.0 253.2 L 559.2 258.1 L 554.6 263.1 L 550.0 268.1 L 545.6 273.2 L 541.3 278.4 L 537.2 283.6 L 533.2 288.9 L 529.3 294.1 L 525.5 299.5 L 521.9 304.9 L 518.3 310.3 L 515.0 315.8 L 511.7 321.2 L 508.6 326.8 L 505.6 332.3 L 502.7 337.9 L 500.0 343.5 L 497.4 349.1 L 494.9 354.7 L 492.6 360.4 L 490.3 366.0 L 488.2 371.7 L 486.3 377.4 L 484.4 383.0 L 482.7 388.7 L 481.1 394.4 L 479.6 400.0 L 478.2 405.7 L 477.0 411.4 L 475.9 417.0 L 474.9 422.6 L 474.0 428.2 L 473.2 433.8 L 472.6 439.4 L 472.0 445.0 L 471.6 450.5 L 471.3 456.0 L 471.1 461.5 L 471.0 466.9 L 471.0 472.3 L 471.1 477.7 L 471.3 483.1 L 471.7 488.4 L 472.1 493.6 L 472.6 498.9 L 473.3 504.0 L 474.0 509.2 L 474.8 514.3 L 475.8 519.3 L 476.8 524.3 L 477.9 529.2 L 479.1 534.1 L 480.4 539.0 L 481.8 543.7 L 483.2 548.5 L 484.8 553.1 L 486.4 557.7 L 488.1 562.3 L 489.9 566.7 L 491.8 571.2 L 493.8 575.5 L 495.8 579.8 L 497.9 584.0 L 500.0 588.2 L 502.3 592.2 L 504.6 596.2 L 506.9 600.2 L 509.3 604.1 L 511.8 607.9 L 514.4 611.6 L 517.0 615.2 L 519.6 618.8 L 522.3 622.3 L 525.1 625.7 L 527.9 629.1 L 530.8 632.4 L 533.7 635.6 L 536.7 638.7 L 539.7 641.7 L 542.7 644.7 L 545.8 647.6 L 548.9 650.4 L 552.1 653.1 L 555.2 655.7 L 558.5 658.3 L 561.7 660.8 L 565.0 663.2 L 568.3 665.5 L 571.6 667.8 L 575.0 669.9 L 578.4 672.0 L 581.8 674.0 L 585.2 676.0 L 588.6 677.8 L 592.1 679.6 L 595.5 681.3 L 599.0 682.9 L 602.5 684.4 L 606.0 685.8 L 609.5 687.2 L 613.0 688.5 L 616.5 689.7 L 620.0 690.9 L 623.5 691.9 L 627.0 692.9 L 630.5 693.9 L 634.0 694.7 L 637.5 695.5 L 641.0 696.1 L 644.5 696.8 L 648.0 697.3 L 651.4 697.8 L 654.9 698.2 L 658.3 698.5 L 661.8 698.8 L 665.2 699.0 L 668.5 699.1 L 671.9 699.1 L 675.3 699.1 L 678.6 699.0 L 681.9 698.9 L 685.2 698.7 L 688.4 698.4 L 691.7 698.1 L 694.9 697.7 L 698.1 697.2 L 701.2 696.7 L 704.3 696.1 L 707.4 695.5 L 710.5 694.8 L 713.5 694.1 L 716.5 693.3 L 719.4 692.4 L 722.4 691.5 L 725.2 690.5 L 728.1 689.5 L 730.9 688.5 L 733.7 687.3 L 736.4 686.2 L 739.1 685.0 L 741.7 683.7 L 744.3 682.4 L 746.9 681.1 L 749.4 679.7 L 751.9 678.3 L 754.3 676.8 L 756.7 675.3 L 759.1 673.8 L 761.4 672.2 L 763.6 670.6 L 765.9 668.9 L 768.0 667.3 L 770.1 665.5 L 772.2 663.8 L 774.2 662.0 L 776.2 660.2 L 778.1 658.4 L 780.0 656.5 L 781.9 654.6 L 783.6 652.7 L 785.4 650.8 L 787.1 648.8 L 788.7 646.9 L 790.3 644.9 L 791.8 642.9 L 793.3 640.8 L 794.7 638.8 L 796.1 636.7 L 797.5 634.6 L 798.8 632.5 L 800.0 630.4 L 801.2 628.3 L 802.3 626.2 L 803.4 624.1 L 804.5 621.9 L 805.5 619.8 L 806.4 617.6 L 807.3 615.4 L 808.2 613.3 L 809.0 611.1 L 809.7 608.9 L 810.4 606.8 L 811.1 604.6 L 811.7 602.4 L 812.2 600.2 L 812.8 598.1 L 813.2 595.9 L 813.7 593.7 L 814.0 591.6 L 814.4 589.4 L 814.7 587.3 L 814.9 585.2 L 815.1 583.0 L 815.3 580.9 L 815.4 578.8 L 815.5 576.7 L 815.5 574.6 L 815.5 572.5 L 815.4 570.5 L 815.3 568.4 L 815.2 566.4 L 815.0 564.4 L 814.8 562.4 L 814.6 560.4 L 814.3 558.4 L 814.0 556.5 L 813.6 554.6 L 813.2 552.6 L 812.8 550.7 L 812.3 548.9 L 811.8 547.0 L 811.3 545.2 L 810.7 543.4 L 810.1 541.6 L 809.5 539.8 L 808.8 538.1 L 808.2 536.4 L 807.4 534.7 L 806.7 533.0 L 805.9 531.4 L 805.1 529.8 L 804.3 528.2 L 803.4 526.6 L 802.5 525.1 L 801.6 523.6 L 800.7 522.1 L 799.7 520.6 L 798.8 519.2 L 797.8 517.8 L 796.7 516.5 L 795.7 515.1 L 794.6 513.8 L 793.5 512.5 L 792.4 511.3 L 791.3 510.0 L 790.2 508.9 L 789.0 507.7 L 787.9 506.6 L 786.7 505.4 L 785.5 504.4 L 784.3 503.3 L 783.0 502.3 L 781.8 501.3 L 780.6 500.4 L 779.3 499.5 L 778.0 498.6 L 776.8 497.7 L 775.5 496.9 L 774.2 496.1 L 772.9 495.3 L 771.5 494.6 L 770.2 493.9 L 768.9 493.2 L 767.6 492.6 L 766.2 491.9 L 764.9 491.4 L 763.6 490.8 L 762.2 490.3 L 760.9 489.8 L 759.5 489.3 L 758.2 488.9 L 756.8 488.5 L 755.5 488.1 L 754.1 487.8 L 752.8 487.4 L 751.4 487.1 L 750.1 486.9 L 748.8 486.6 L 747.4 486.4 L 746.1 486.3 L 744.8 486.1 L 743.5 486.0 L 742.1 485.9 L 740.8 485.8 L 739.5 485.8 L 738.2 485.8 L 737.0 485.8 L 735.7 485.8 L 734.4 485.9 L 733.2 485.9 L 731.9 486.0 L 730.7 486.2 L 729.4 486.3 L 728.2 486.5 L 727.0 486.7 L 725.8 486.9 L 724.6 487.2 L 723.4 487.4 L 722.3 487.7 L 721.1 488.0 L 720.0 488.4 L 718.9 488.7 L 717.8 489.1 L 716.7 489.5 L 715.6 489.9 L 714.5 490.3 L 713.5 490.8 L 712.5 491.2 L 711.4 491.7 L 710.4 492.2 L 709.5 492.7 L 708.5 493.3 L 707.5 493.8 L 706.6 494.4 L 705.7 495.0 L 704.8 495.6 L 703.9 496.2 L 703.0 496.8 L 702.2 497.4 L 701.4 498.1 L 700.5 498.7 L 699.7 499.4 L 699.0 500.1 L 698.2 500.8 L 697.5 501.5 L 696.7 502.2 L 696.0 502.9 L 695.4 503.7 L 694.7 504.4 L 694.0 505.2 L 693.4 505.9 L 692.8 506.7 L 692.2 507.5 L 691.6 508.2 L 691.1 509.0 L 690.6 509.8 L 690.1 510.6 L 689.6 511.4 L 689.1 512.3 L 688.6 513.1 L 688.2 513.9 L 687.8 514.7 L 687.4 515.5 L 687.0 516.4 L 686.6 517.2 L 686.3 518.0 L 686.0 518.9 L 685.6 519.7 L 685.4 520.5 L 685.1 521.4 L 684.8 522.2 L 684.6 523.0 L 684.4 523.9 L 684.2 524.7 L 684.0 525.6 L 683.8 526.4 L 683.7 527.2 L 683.6 528.0 L 683.5 528.9 L 683.4 529.7 L 683.3 530.5 L 683.2 531.3 L 683.2 532.1 L 683.2 532.9 L 683.2 533.8 L 683.2 534.6 L 683.2 535.3 L 683.2 536.1 L 683.3 536.9 L 683.3 537.7 L 683.4 538.5 L 683.5 539.2 L 683.6 540.0 L 683.8 540.7 L 683.9 541.5 L 684.0 542.2 L 684.2 543.0 L 684.4 543.7 L 684.6 544.4 L 684.8 545.1 L 685.0 545.8 L 685.2 546.5 L 685.5 547.2 L 685.7 547.8 L 686.0 548.5 L 686.3 549.1 L 686.6 549.8 L 686.9 550.4 L 687.2 551.0 L 687.5 551.6 L 687.8 552.2 L 688.2 552.8 L 688.5 553.4 L 688.9 554.0 L 689.3 554.6 L 689.6 555.1 L 690.0 555.6 L 690.4 556.2 L 690.8 556.7 L 691.2 557.2 L 691.7 557.7 L 692.1 558.2 L 692.5 558.6 L 693.0 559.1 L 693.4 559.6 L 693.9 560.0 L 694.3 560.4 L 694.8 560.8 L 695.2 561.2 L 695.7 561.6 L 696.2 562.0 L 696.7 562.4 L 697.2 562.7 L 697.7 563.1 L 698.2 563.4 L 698.7 563.7 L 699.2 564.0 L 699.7 564.3 L 700.2 564.6 L 700.7 564.9 L 701.2 565.1 L 701.7 565.4 L 702.2 565.6 L 702.7 565.8 L 703.3 566.1 L 703.8 566.3 L 704.3 566.5 L 704.8 566.6 L 705.3 566.8 L 705.9 567.0 L 706.4 567.1 L 706.9 567.2 L 707.4 567.4 L 708.0 567.5 L 708.5 567.6 L 709.0 567.7 L 709.5 567.7 L 710.0 567.8 L 710.5 567.9 L 711.0 567.9 L 711.6 568.0 L 712.1 568.0 L 712.6 568.0 L 713.1 568.0 L 713.6 568.0 L 714.1 568.0 L 714.6 568.0 L 715.0 567.9 L 715.5 567.9 L 716.0 567.8 L 716.5 567.8 L 717.0 567.7 L 717.4 567.6 L 717.9 567.5 L 718.3 567.4 L 718.8 567.3 L 719.3 567.2 L 719.7 567.1 L 720.1 567.0 L 720.6 566.8 L 721.0 566.7 L 721.4 566.5 L 721.8 566.4 L 722.3 566.2 L 722.7 566.0 L 723.1 565.9 L 723.5 565.7 L 723.8 565.5 L 724.2 565.3 L 724.6 565.1 L 725.0 564.9 L 725.3 564.6 L 725.7 564.4 L 726.0 564.2 L 726.4 563.9 L 726.7 563.7 L 727.1 563.4 L 727.4 563.2 L 727.7 562.9 L 728.0 562.7 L 728.3 562.4 L 728.6 562.1 L 728.9 561.9 L 729.2 561.6 L 729.4 561.3 L 729.7 561.0 L 730.0 560.7 L 730.2 560.4 L 730.5 560.1 L 730.7 559.8 L 730.9 559.5 L 731.1 559.2 L 731.4 558.9 L 731.6 558.6 L 731.8 558.3 L 732.0 558.0 L 732.1 557.7 L 732.3 557.4 L 732.5 557.0 L 732.7 556.7 L 732.8 556.4 L 733.0 556.1 L 733.1 555.7 L 733.2 555.4 L 733.4 555.1 L 733.5 554.8 L 733.6 554.4 L 733.7 554.1 L 733.8 553.8 L 733.9 553.5 L 734.0 553.1 L 734.0 552.8 L 734.1 552.5 L 734.2 552.2 L 734.2 551.8 L 734.3 551.5 L 734.3 551.2 L 734.4 550.9 L 734.4 550.5 L 734.4 550.2 L 734.4 549.9 L 734.4 549.6 L 734.4 549.3 L 734.4 549.0 L 734.4 548.7 L 734.4 548.3 L 734.4 548.0 L 734.4 547.7 L 734.3 547.4 L 734.3 547.1 L 734.3 546.8 L 734.2 546.5 L 734.2 546.3 L 734.1 546.0 L 734.0 545.7 L 734.0 545.4 L 733.9 545.1 L 733.8 544.8 L 733.7 544.6 L 733.6 544.3 L 733.5 544.0 L 733.4 543.8 L 733.3 543.5 L 733.2 543.3 L 733.1 543.0 L 733.0 542.8 L 732.9 542.5 L 732.7 542.3 L 732.6 542.0 L 732.5 541.8 L 732.3 541.6 L 732.2 541.4 L 732.0 541.1 L 731.9 540.9 L 731.7 540.7 L 731.6 540.5 L 731.4 540.3 L 731.3 540.1 L 731.1 539.9 L 730.9 539.7 L 730.8 539.5 L 730.6 539.3 L 730.4 539.2 L 730.2 539.0 L 730.1 538.8 L 729.9 538.7 L 729.7 538.5 L 729.5 538.4 L 729.3 538.2 L 729.1 538.1 L 728.9 537.9 L 728.7 537.8 L 728.5 537.7 L 728.3 537.5 L 728.1 537.4 L 727.9 537.3 L 727.7 537.2 L 727.5 537.1 L 727.3 537.0 L 727.1 536.9 L 726.9 536.8 L 726.7 536.7 L 726.5 536.6 L 726.3 536.5 L 726.1 536.5 L 725.9 536.4 L 725.7 536.3 L 725.5 536.3 L 725.3 536.2 L 725.1 536.1 L 724.9 536.1 L 724.7 536.1 L 724.5 536.0 L 724.3 536.0 L 724.1 535.9 L 723.9 535.9 L 723.6 535.9 L 723.4 535.9 L 723.2 535.9 L 723.0 535.9 L 722.8 535.8 L 722.6 535.8 L 722.4 535.8 L 722.3 535.9 L 722.1 535.9 L 721.9 535.9 L 721.7 535.9 L 721.5 535.9 L 721.3 535.9 L 721.1 536.0 L 720.9 536.0 L 720.7 536.0 L 720.5 536.1 L 720.4 536.1 L 720.2 536.2 L 720.0 536.2 L 719.8 536.3 L 719.7 536.3 L 719.5 536.4 L 719.3 536.4 L 719.2 536.5 L 719.0 536.6 L 718.8 536.6 L 718.7 536.7 L 718.5 536.8 L 718.4 536.9 L 718.2 536.9 L 718.1 537.0 L 717.9 537.1 L 717.8 537.2 L 717.6 537.3 L 717.5 537.4 L 717.3 537.5 L 717.2 537.6 L 717.1 537.7 L 717.0 537.8 L 716.8 537.9 L 716.7 538.0 L 716.6 538.1 L 716.5 538.2 L 716.3 538.3 L 716.2 538.4 L 716.1 538.5 L 716.0 538.6 L 715.9 538.7 L 715.8 538.9 L 715.7 539.0 L 715.6 539.1 L 715.5 539.2 L 715.4 539.3 L 715.4 539.5 L 715.3 539.6 L 715.2 539.7 L 715.1 539.8 L 715.0 540.0 L 715.0 540.1 L 714.9 540.2 L 714.8 540.4 L 714.8 540.5 L 714.7 540.6 L 714.7 540.8 L 714.6 540.9 L 714.6 541.0 L 714.5 541.1 L 714.5 541.3 L 714.4 541.4 L 714.4 541.5 L 714.3 541.7 L 714.3 541.8 L 714.3 541.9 L 714.2 542.1 L 714.2 542.2 L 714.2 542.3 L 714.2 542.5 L 714.2 542.6 L 714.1 542.7 L 714.1 542.8 L 714.1 543.0 L 714.1 543.1 L 714.1 543.2 L 714.1 543.4 L 714.1 543.5 L 714.1 543.6 L 714.1 543.7 L 714.1 543.9 L 714.1 544.0 L 714.2 544.1 L 714.2 544.2 L 714.2 544.4 L 714.2 544.5 L 714.2 544.6 L 714.3 544.7 L 714.3 544.8 L 714.3 544.9 L 714.3 545.1 L 714.4 545.2 L 714.4 545.3 L 714.4 545.4 L 714.5 545.5 L 714.5 545.6 L 714.6 545.7 L 714.6 545.8 L 714.7 545.9 L 714.7 546.0 L 714.8 546.1 L 714.8 546.2 L 714.9 546.3 L 714.9 546.4 L 715.0 546.5 L 715.0 546.6 L 715.1 546.7 L 715.2 546.8 L 715.2 546.9 L 715.3 546.9 L 715.3 547.0 L 715.4 547.1 L 715.5 547.2 L 715.5 547.3 L 715.6 547.3 L 715.7 547.4 L 715.8 547.5 L 715.8 547.6 L 715.9 547.6 L 716.0 547.7 L 716.1 547.8 L 716.1 547.8 L 716.2 547.9 L 716.3 547.9 L 716.4 548.0 L 716.5 548.1 L 716.5 548.1 L 716.6 548.2 L 716.7 548.2 L 716.8 548.3 L 716.9 548.3 L 716.9 548.4 L 717.0 548.4 L 717.1 548.4 L 717.2 548.5 L 717.3 548.5 L 717.4 548.5 L 717.5 548.6 L 717.5 548.6 L 717.6 548.6 L 717.7 548.7 L 717.8 548.7 L 717.9 548.7 L 718.0 548.7 L 718.1 548.8 L 718.1 548.8 L 718.2 548.8 L 718.3 548.8 L 718.4 548.8 L 718.5 548.8 L 718.6 548.8 L 718.6 548.9 L 718.7 548.9 L 718.8 548.9 L 718.9 548.9 L 719.0 548.9 L 719.1 548.9 L 719.1 548.9 L 719.2 548.9 L 719.3 548.9 L 719.4 548.8 L 719.5 548.8 L 719.6 548.8 L 719.6 548.8 L 719.7 548.8 L 719.8 548.8 L 719.9 548.8 L 719.9 548.8 L 720.0 548.7 L 720.1 548.7 L 720.2 548.7 L 720.2 548.7 L 720.3 548.7 L 720.4 548.6 L 720.5 548.6 L 720.5 548.6 L 720.6 548.5 L 720.7 548.5 L 720.7 548.5 L 720.8 548.4 L 720.9 548.4 L 720.9 548.4 L 721.0 548.3 L 721.0 548.3 L 721.1 548.3 L 721.2 548.2 L 721.2 548.2 L 721.3 548.1 L 721.3 548.1 L 721.4 548.1 L 721.4 548.0 L 721.5 548.0 L 721.5 547.9 L 721.6 547.9 L 721.6 547.8 L 721.7 547.8 L 721.7 547.7 L 721.8 547.7 L 721.8 547.6 L 721.9 547.6 L 721.9 547.5 L 722.0 547.5 L 722.0 547.4 L 722.0 547.4 L 722.1 547.3 L 722.1 547.3 L 722.1 547.2 L 722.2 547.2 L 722.2 547.1 L 722.2 547.1 L 722.3 547.0 L 722.3 546.9 L 722.3 546.9 L 722.4 546.8 L 722.4 546.8 L 722.4 546.7 L 722.4 546.7 L 722.4 546.6 L 722.5 546.5 L 722.5 546.5 L 722.5 546.4 L 722.5 546.4 L 722.5 546.3 L 722.5 546.3 L 722.6 546.2 L 722.6 546.1 L 722.6 546.1 L 722.6 546.0 L 722.6 546.0 L 722.6 545.9 L 722.6 545.9 L 722.6 545.8 L 722.6 545.7 L 722.6 545.7 L 722.6 545.6 L 722.6 545.6 L 722.6 545.5 L 722.6 545.5 L 722.6 545.4 L 722.6 545.4 L 722.6 545.3 L 722.6 545.3 L 722.6 545.2 L 722.6 545.1 L 722.6 545.1 L 722.6 545.0 L 722.5 545.0 L 722.5 544.9 L 722.5 544.9 L 722.5 544.8 L 722.5 544.8 L 722.5 544.7 L 722.5 544.7 L 722.4 544.6 L 722.4 544.6 L 722.4 544.5 L 722.4 544.5 L 722.4 544.5 L 722.3 544.4 L 722.3 544.4 L 722.3 544.3 L 722.3 544.3 L 722.2 544.2 L 722.2 544.2 L 722.2 544.2 L 722.2 544.1 L 722.1 544.1 L 720.7 545.0 L 720.7 545.1 L 720.7 545.1 L 720.7 545.1 L 720.7 545.1 L 720.8 545.1 L 720.8 545.1 L 720.8 545.1 L 720.8 545.1 L 720.8 545.2 L 720.8 545.2 L 720.8 545.2 L 720.8 545.2 L 720.8 545.2 L 720.8 545.2 L 720.8 545.3 L 720.8 545.3 L 720.8 545.3 L 720.8 545.3 L 720.8 545.3 L 720.8 545.3 L 720.8 545.4 L 720.8 545.4 L 720.8 545.4 L 720.8 545.4 L 720.8 545.4 L 720.8 545.4 L 720.8 545.5 L 720.8 545.5 L 720.8 545.5 L 720.8 545.5 L 720.8 545.5 L 720.8 545.6 L 720.8 545.6 L 720.8 545.6 L 720.8 545.6 L 720.8 545.6 L 720.8 545.7 L 720.8 545.7 L 720.8 545.7 L 720.8 545.7 L 720.8 545.7 L 720.8 545.8 L 720.7 545.8 L 720.7 545.8 L 720.7 545.8 L 720.7 545.8 L 720.7 545.9 L 720.7 545.9 L 720.7 545.9 L 720.7 545.9 L 720.7 546.0 L 720.7 546.0 L 720.6 546.0 L 720.6 546.0 L 720.6 546.0 L 720.6 546.1 L 720.6 546.1 L 720.6 546.1 L 720.6 546.1 L 720.5 546.1 L 720.5 546.2 L 720.5 546.2 L 720.5 546.2 L 720.5 546.2 L 720.5 546.2 L 720.4 546.3 L 720.4 546.3 L 720.4 546.3 L 720.4 546.3 L 720.4 546.3 L 720.3 546.3 L 720.3 546.4 L 720.3 546.4 L 720.3 546.4 L 720.2 546.4 L 720.2 546.4 L 720.2 546.4 L 720.2 546.5 L 720.1 546.5 L 720.1 546.5 L 720.1 546.5 L 720.1 546.5 L 720.0 546.5 L 720.0 546.5 L 720.0 546.6 L 719.9 546.6 L 719.9 546.6 L 719.9 546.6 L 719.9 546.6 L 719.8 546.6 L 719.8 546.6 L 719.8 546.6 L 719.7 546.6 L 719.7 546.6 L 719.7 546.6 L 719.6 546.7 L 719.6 546.7 L 719.6 546.7 L 719.5 546.7 L 719.5 546.7 L 719.4 546.7 L 719.4 546.7 L 719.4 546.7 L 719.3 546.7 L 719.3 546.7 L 719.3 546.7 L 719.2 546.7 L 719.2 546.7 L 719.1 546.7 L 719.1 546.7 L 719.1 546.7 L 719.0 546.7 L 719.0 546.7 L 719.0 546.7 L 718.9 546.6 L 718.9 546.6 L 718.8 546.6 L 718.8 546.6 L 718.8 546.6 L 718.7 546.6 L 718.7 546.6 L 718.6 546.6 L 718.6 546.6 L 718.6 546.5 L 718.5 546.5 L 718.5 546.5 L 718.4 546.5 L 718.4 546.5 L 718.3 546.4 L 718.3 546.4 L 718.3 546.4 L 718.2 546.4 L 718.2 546.4 L 718.1 546.3 L 718.1 546.3 L 718.1 546.3 L 718.0 546.3 L 718.0 546.2 L 718.0 546.2 L 717.9 546.2 L 717.9 546.1 L 717.8 546.1 L 717.8 546.1 L 717.8 546.0 L 717.7 546.0 L 717.7 546.0 L 717.7 545.9 L 717.6 545.9 L 717.6 545.8 L 717.6 545.8 L 717.5 545.8 L 717.5 545.7 L 717.5 545.7 L 717.4 545.6 L 717.4 545.6 L 717.4 545.5 L 717.3 545.5 L 717.3 545.4 L 717.3 545.4 L 717.3 545.3 L 717.2 545.3 L 717.2 545.2 L 717.2 545.2 L 717.2 545.1 L 717.1 545.1 L 717.1 545.0 L 717.1 545.0 L 717.1 544.9 L 717.1 544.8 L 717.0 544.8 L 717.0 544.7 L 717.0 544.7 L 717.0 544.6 L 717.0 544.5 L 717.0 544.5 L 716.9 544.4 L 716.9 544.4 L 716.9 544.3 L 716.9 544.2 L 716.9 544.2 L 716.9 544.1 L 716.9 544.0 L 716.9 544.0 L 716.9 543.9 L 716.9 543.8 L 716.9 543.8 L 716.9 543.7 L 716.9 543.6 L 716.9 543.5 L 716.9 543.5 L 716.9 543.4 L 716.9 543.3 L 717.0 543.3 L 717.0 543.2 L 717.0 543.1 L 717.0 543.1 L 717.0 543.0 L 717.0 542.9 L 717.1 542.8 L 717.1 542.8 L 717.1 542.7 L 717.1 542.6 L 717.2 542.5 L 717.2 542.5 L 717.2 542.4 L 717.2 542.3 L 717.3 542.3 L 717.3 542.2 L 717.4 542.1 L 717.4 542.0 L 717.4 542.0 L 717.5 541.9 L 717.5 541.8 L 717.6 541.8 L 717.6 541.7 L 717.7 541.6 L 717.7 541.5 L 717.8 541.5 L 717.8 541.4 L 717.9 541.3 L 717.9 541.3 L 718.0 541.2 L 718.1 541.1 L 718.1 541.1 L 718.2 541.0 L 718.2 541.0 L 718.3 540.9 L 718.4 540.8 L 718.5 540.8 L 718.5 540.7 L 718.6 540.7 L 718.7 540.6 L 718.8 540.5 L 718.8 540.5 L 718.9 540.4 L 719.0 540.4 L 719.1 540.3 L 719.2 540.3 L 719.3 540.2 L 719.3 540.2 L 719.4 540.2 L 719.5 540.1 L 719.6 540.1 L 719.7 540.0 L 719.8 540.0 L 719.9 540.0 L 720.0 539.9 L 720.1 539.9 L 720.2 539.9 L 720.3 539.8 L 720.4 539.8 L 720.5 539.8 L 720.6 539.7 L 720.7 539.7 L 720.9 539.7 L 721.0 539.7 L 721.1 539.7 L 721.2 539.7 L 721.3 539.6 L 721.4 539.6 L 721.5 539.6 L 721.6 539.6 L 721.8 539.6 L 721.9 539.6 L 722.0 539.6 L 722.1 539.6 L 722.2 539.6 L 722.4 539.6 L 722.5 539.7 L 722.6 539.7 L 722.7 539.7 L 722.8 539.7 L 723.0 539.7 L 723.1 539.8 L 723.2 539.8 L 723.3 539.8 L 723.5 539.8 L 723.6 539.9 L 723.7 539.9 L 723.8 540.0 L 724.0 540.0 L 724.1 540.0 L 724.2 540.1 L 724.3 540.1 L 724.5 540.2 L 724.6 540.3 L 724.7 540.3 L 724.8 540.4 L 725.0 540.5 L 725.1 540.5 L 725.2 540.6 L 725.3 540.7 L 725.4 540.7 L 725.6 540.8 L 725.7 540.9 L 725.8 541.0 L 725.9 541.1 L 726.0 541.2 L 726.1 541.3 L 726.3 541.4 L 726.4 541.5 L 726.5 541.6 L 726.6 541.7 L 726.7 541.8 L 726.8 541.9 L 726.9 542.0 L 727.0 542.1 L 727.1 542.3 L 727.2 542.4 L 727.3 542.5 L 727.4 542.6 L 727.5 542.8 L 727.6 542.9 L 727.7 543.0 L 727.8 543.2 L 727.9 543.3 L 727.9 543.5 L 728.0 543.6 L 728.1 543.8 L 728.2 543.9 L 728.2 544.1 L 728.3 544.2 L 728.4 544.4 L 728.4 544.6 L 728.5 544.7 L 728.6 544.9 L 728.6 545.1 L 728.7 545.2 L 728.7 545.4 L 728.8 545.6 L 728.8 545.8 L 728.9 545.9 L 728.9 546.1 L 728.9 546.3 L 729.0 546.5 L 729.0 546.7 L 729.0 546.9 L 729.0 547.1 L 729.0 547.2 L 729.1 547.4 L 729.1 547.6 L 729.1 547.8 L 729.1 548.0 L 729.1 548.2 L 729.1 548.4 L 729.1 548.6 L 729.0 548.8 L 729.0 549.0 L 729.0 549.2 L 729.0 549.5 L 728.9 549.7 L 728.9 549.9 L 728.9 550.1 L 728.8 550.3 L 728.8 550.5 L 728.7 550.7 L 728.6 550.9 L 728.6 551.1 L 728.5 551.3 L 728.4 551.5 L 728.4 551.7 L 728.3 552.0 L 728.2 552.2 L 728.1 552.4 L 728.0 552.6 L 727.9 552.8 L 727.8 553.0 L 727.7 553.2 L 727.6 553.4 L 727.5 553.6 L 727.3 553.8 L 727.2 554.0 L 727.1 554.2 L 726.9 554.4 L 726.8 554.6 L 726.6 554.8 L 726.5 555.0 L 726.3 555.2 L 726.2 555.4 L 726.0 555.5 L 725.8 555.7 L 725.6 555.9 L 725.5 556.1 L 725.3 556.3 L 725.1 556.4 L 724.9 556.6 L 724.7 556.8 L 724.5 557.0 L 724.3 557.1 L 724.1 557.3 L 723.8 557.4 L 723.6 557.6 L 723.4 557.7 L 723.1 557.9 L 722.9 558.0 L 722.7 558.2 L 722.4 558.3 L 722.2 558.4 L 721.9 558.6 L 721.7 558.7 L 721.4 558.8 L 721.1 558.9 L 720.9 559.0 L 720.6 559.1 L 720.3 559.2 L 720.0 559.3 L 719.7 559.4 L 719.5 559.5 L 719.2 559.6 L 718.9 559.6 L 718.6 559.7 L 718.3 559.8 L 718.0 559.8 L 717.7 559.9 L 717.3 559.9 L 717.0 560.0 L 716.7 560.0 L 716.4 560.0 L 716.1 560.0 L 715.7 560.0 L 715.4 560.1 L 715.1 560.1 L 714.8 560.0 L 714.4 560.0 L 714.1 560.0 L 713.8 560.0 L 713.4 560.0 L 713.1 559.9 L 712.7 559.9 L 712.4 559.8 L 712.1 559.8 L 711.7 559.7 L 711.4 559.6 L 711.0 559.5 L 710.7 559.4 L 710.3 559.3 L 710.0 559.2 L 709.7 559.1 L 709.3 559.0 L 709.0 558.9 L 708.6 558.7 L 708.3 558.6 L 707.9 558.5 L 707.6 558.3 L 707.2 558.1 L 706.9 558.0 L 706.6 557.8 L 706.2 557.6 L 705.9 557.4 L 705.6 557.2 L 705.2 557.0 L 704.9 556.7 L 704.6 556.5 L 704.3 556.3 L 703.9 556.0 L 703.6 555.8 L 703.3 555.5 L 703.0 555.2 L 702.7 555.0 L 702.4 554.7 L 702.1 554.4 L 701.8 554.1 L 701.5 553.8 L 701.2 553.5 L 700.9 553.1 L 700.6 552.8 L 700.4 552.5 L 700.1 552.1 L 699.8 551.8 L 699.6 551.4 L 699.3 551.0 L 699.1 550.7 L 698.8 550.3 L 698.6 549.9 L 698.4 549.5 L 698.2 549.1 L 697.9 548.7 L 697.7 548.3 L 697.5 547.8 L 697.3 547.4 L 697.2 547.0 L 697.0 546.5 L 696.8 546.1 L 696.6 545.6 L 696.5 545.2 L 696.3 544.7 L 696.2 544.2 L 696.1 543.7 L 696.0 543.2 L 695.9 542.8 L 695.8 542.3 L 695.7 541.8 L 695.6 541.3 L 695.5 540.7 L 695.4 540.2 L 695.4 539.7 L 695.3 539.2 L 695.3 538.7 L 695.3 538.1 L 695.3 537.6 L 695.3 537.1 L 695.3 536.5 L 695.3 536.0 L 695.3 535.4 L 695.4 534.9 L 695.4 534.3 L 695.5 533.8 L 695.6 533.2 L 695.7 532.6 L 695.8 532.1 L 695.9 531.5 L 696.0 531.0 L 696.1 530.4 L 696.3 529.8 L 696.4 529.3 L 696.6 528.7 L 696.8 528.1 L 697.0 527.6 L 697.2 527.0 L 697.4 526.4 L 697.7 525.9 L 697.9 525.3 L 698.2 524.8 L 698.4 524.2 L 698.7 523.6 L 699.0 523.1 L 699.3 522.5 L 699.7 522.0 L 700.0 521.4 L 700.3 520.9 L 700.7 520.4 L 701.1 519.8 L 701.5 519.3 L 701.9 518.8 L 702.3 518.3 L 702.7 517.7 L 703.2 517.2 L 703.6 516.7 L 704.1 516.2 L 704.6 515.7 L 705.0 515.2 L 705.6 514.8 L 706.1 514.3 L 706.6 513.8 L 707.1 513.4 L 707.7 512.9 L 708.3 512.5 L 708.8 512.1 L 709.4 511.6 L 710.0 511.2 L 710.6 510.8 L 711.3 510.4 L 711.9 510.1 L 712.6 509.7 L 713.2 509.3 L 713.9 509.0 L 714.6 508.6 L 715.3 508.3 L 716.0 508.0 L 716.7 507.7 L 717.4 507.4 L 718.2 507.1 L 718.9 506.9 L 719.7 506.6 L 720.4 506.4 L 721.2 506.1 L 722.0 505.9 L 722.8 505.7 L 723.6 505.6 L 724.4 505.4 L 725.2 505.2 L 726.0 505.1 L 726.9 505.0 L 727.7 504.9 L 728.5 504.8 L 729.4 504.7 L 730.3 504.7 L 731.1 504.6 L 732.0 504.6 L 732.9 504.6 L 733.8 504.6 L 734.7 504.7 L 735.6 504.7 L 736.5 504.8 L 737.4 504.9 L 738.3 505.0 L 739.2 505.1 L 740.1 505.3 L 741.0 505.4 L 741.9 505.6 L 742.8 505.8 L 743.8 506.0 L 744.7 506.3 L 745.6 506.5 L 746.5 506.8 L 747.4 507.1 L 748.4 507.4 L 749.3 507.8 L 750.2 508.1 L 751.1 508.5 L 752.0 508.9 L 752.9 509.3 L 753.9 509.8 L 754.8 510.3 L 755.7 510.7 L 756.6 511.3 L 757.5 511.8 L 758.3 512.3 L 759.2 512.9 L 760.1 513.5 L 761.0 514.1 L 761.8 514.7 L 762.7 515.4 L 763.5 516.1 L 764.4 516.8 L 765.2 517.5 L 766.0 518.2 L 766.8 519.0 L 767.6 519.8 L 768.4 520.6 L 769.2 521.4 L 770.0 522.2 L 770.7 523.1 L 771.5 524.0 L 772.2 524.9 L 772.9 525.8 L 773.6 526.8 L 774.3 527.7 L 775.0 528.7 L 775.6 529.7 L 776.3 530.7 L 776.9 531.8 L 777.5 532.8 L 778.1 533.9 L 778.6 535.0 L 779.2 536.1 L 779.7 537.2 L 780.2 538.4 L 780.7 539.5 L 781.2 540.7 L 781.7 541.9 L 782.1 543.1 L 782.5 544.4 L 782.9 545.6 L 783.2 546.9 L 783.6 548.2 L 783.9 549.4 L 784.2 550.8 L 784.5 552.1 L 784.7 553.4 L 784.9 554.7 L 785.1 556.1 L 785.3 557.5 L 785.4 558.8 L 785.5 560.2 L 785.6 561.6 L 785.7 563.1 L 785.7 564.5 L 785.7 565.9 L 785.7 567.3 L 785.6 568.8 L 785.5 570.2 L 785.4 571.7 L 785.3 573.2 L 785.1 574.6 L 784.9 576.1 L 784.7 577.6 L 784.4 579.1 L 784.1 580.6 L 783.8 582.1 L 783.4 583.6 L 783.0 585.1 L 782.6 586.6 L 782.1 588.1 L 781.6 589.6 L 781.1 591.1 L 780.6 592.6 L 780.0 594.1 L 779.3 595.6 L 778.7 597.0 L 778.0 598.5 L 777.3 600.0 L 776.5 601.5 L 775.7 602.9 L 774.9 604.4 L 774.0 605.9 L 773.1 607.3 L 772.2 608.7 L 771.2 610.2 L 770.2 611.6 L 769.2 613.0 L 768.1 614.4 L 767.0 615.7 L 765.9 617.1 L 764.7 618.5 L 763.5 619.8 L 762.3 621.1 L 761.0 622.4 L 759.7 623.7 L 758.4 624.9 L 757.0 626.2 L 755.6 627.4 L 754.2 628.6 L 752.7 629.8 L 751.2 631.0 L 749.7 632.1 L 748.1 633.2 L 746.5 634.3 L 744.9 635.4 L 743.2 636.4 L 741.5 637.4 L 739.8 638.4 L 738.1 639.3 L 736.3 640.3 L 734.5 641.1 L 732.6 642.0 L 730.8 642.8 L 728.9 643.6 L 727.0 644.4 L 725.0 645.1 L 723.0 645.8 L 721.0 646.5 L 719.0 647.1 L 717.0 647.7 L 714.9 648.3 L 712.8 648.8 L 710.7 649.2 L 708.5 649.7 L 706.4 650.1 L 704.2 650.4 L 702.0 650.7 L 699.8 651.0 L 697.5 651.2 L 695.3 651.4 L 693.0 651.5 L 690.7 651.6 L 688.4 651.7 L 686.1 651.7 L 683.7 651.6 L 681.4 651.5 L 679.0 651.4 L 676.7 651.2 L 674.3 651.0 L 671.9 650.7 L 669.5 650.4 L 667.1 650.0 L 664.7 649.5 L 662.2 649.1 L 659.8 648.5 L 657.4 647.9 L 654.9 647.3 L 652.5 646.6 L 650.1 645.9 L 647.6 645.1 L 645.2 644.2 L 642.8 643.3 L 640.4 642.3 L 637.9 641.3 L 635.5 640.2 L 633.1 639.1 L 630.7 637.9 L 628.3 636.7 L 626.0 635.4 L 623.6 634.1 L 621.2 632.7 L 618.9 631.2 L 616.6 629.7 L 614.3 628.1 L 612.0 626.5 L 609.7 624.8 L 607.4 623.1 L 605.2 621.3 L 603.0 619.5 L 600.8 617.6 L 598.6 615.6 L 596.5 613.6 L 594.4 611.6 L 592.3 609.4 L 590.3 607.3 L 588.3 605.0 L 586.3 602.8 L 584.3 600.4 L 582.4 598.0 L 580.5 595.6 L 578.7 593.1 L 576.9 590.6 L 575.1 588.0 L 573.4 585.3 L 571.7 582.6 L 570.1 579.9 L 568.5 577.1 L 567.0 574.3 L 565.5 571.4 L 564.0 568.4 L 562.6 565.5 L 561.3 562.4 L 560.0 559.4 L 558.8 556.3 L 557.6 553.1 L 556.5 549.9 L 555.4 546.6 L 554.4 543.4 L 553.4 540.0 L 552.5 536.7 L 551.7 533.3 L 550.9 529.8 L 550.2 526.4 L 549.6 522.9 L 549.0 519.3 L 548.5 515.7 L 548.1 512.1 L 547.7 508.5 L 547.5 504.8 L 547.2 501.2 L 547.1 497.4 L 547.0 493.7 L 547.0 489.9 L 547.1 486.1 L 547.2 482.3 L 547.5 478.5 L 547.8 474.7 L 548.2 470.8 L 548.6 466.9 L 549.2 463.0 L 549.8 459.1 L 550.5 455.2 L 551.3 451.3 L 552.2 447.3 L 553.1 443.4 L 554.2 439.5 L 555.3 435.5 L 556.5 431.6 L 557.8 427.6 L 559.2 423.7 L 560.7 419.7 L 562.2 415.8 L 563.9 411.9 L 565.6 408.0 L 567.5 404.1 L 569.4 400.2 L 571.4 396.3 L 573.5 392.5 L 575.7 388.6 L 577.9 384.8 L 580.3 381.0 L 582.7 377.2 L 585.3 373.5 L 587.9 369.8 L 590.6 366.1 L 593.5 362.5 L 596.4 358.8 L 599.3 355.3 L 602.4 351.7 L 605.6 348.2 L 608.9 344.8 L 612.2 341.4 L 615.6 338.0 L 619.2 334.7 L 622.8 331.4 L 626.5 328.2 L 630.3 325.0 L 634.1 321.9 L 638.1 318.9 L 642.1 315.9 L 646.2 313.0 L 650.5 310.2 L 654.7 307.4 L 659.1 304.7 L 663.6 302.0 L 668.1 299.4 L 672.7 297.0 L 677.4 294.5 L 682.1 292.2 L 687.0 289.9 L 691.9 287.8 L 696.9 285.7 L 701.9 283.7 L 707.0 281.8 L 712.2 279.9 L 717.5 278.2 L 722.8 276.6 L 728.2 275.1 L 733.6 273.6 L 739.2 272.3 L 744.7 271.0 L 750.4 269.9 L 756.0 268.9 L 761.8 268.0 L 767.6 267.2 L 773.4 266.5 L 779.3 265.9 L 785.2 265.4 L 791.2 265.1 L 797.2 264.8 L 803.3 264.7 L 809.4 264.7 L 815.6 264.9 L 821.7 265.1 L 827.9 265.5 L 834.2 266.0 Z" fill="url(#rib)"/&gt;
&lt;line x1="774.0" y1="148.0" x2="781.0" y2="96.5" stroke="#3a3e4d" stroke-width="1.5"/&gt;&lt;circle cx="774.0" cy="148.0" r="4.5" fill="#8aa4ff"/&gt;&lt;text x="781.0" y="90.5" text-anchor="middle" font-size="25" fill="#e6e8ee" font-weight="700"&gt;AWS · CloudFormation&lt;/text&gt;
&lt;line x1="509.3" y1="325.5" x2="473.3" y2="288.0" stroke="#3a3e4d" stroke-width="1.5"/&gt;&lt;circle cx="509.3" cy="325.5" r="4.5" fill="#8aa4ff"/&gt;&lt;text x="467.3" y="282.0" text-anchor="end" font-size="23" fill="#e6e8ee" font-weight="700"&gt;Kubernetes&lt;/text&gt;
&lt;line x1="489.9" y1="566.8" x2="438.2" y2="571.7" stroke="#3a3e4d" stroke-width="1.5"/&gt;&lt;circle cx="489.9" cy="566.8" r="4.5" fill="#8aa4ff"/&gt;&lt;text x="432.2" y="577.7" text-anchor="end" font-size="23" fill="#e6e8ee" font-weight="700"&gt;Azure · GCP&lt;/text&gt;
&lt;line x1="624.4" y1="692.2" x2="596.0" y2="735.8" stroke="#3a3e4d" stroke-width="1.5"/&gt;&lt;circle cx="624.4" cy="692.2" r="4.5" fill="#8aa4ff"/&gt;&lt;text x="590.0" y="753.8" text-anchor="end" font-size="22" fill="#e6e8ee" font-weight="700"&gt;GitHub Actions · CI&lt;/text&gt;
&lt;line x1="809.9" y1="541.1" x2="901.9" y2="537.0" stroke="#3a3e4d" stroke-width="1.5"/&gt;&lt;circle cx="809.9" cy="541.1" r="3.5" fill="#8aa4ff"/&gt;&lt;text x="907.9" y="542.0" text-anchor="start" font-size="19" font-style="italic" fill="#8b8fa3"&gt;spec-less APIs&lt;/text&gt;
&lt;circle cx="720" cy="545" r="3" fill="#8aa4ff"/&gt;&lt;line x1="720" y1="545" x2="840" y2="715" stroke="#3a3e4d" stroke-width="1.5"/&gt;&lt;text x="848" y="721" text-anchor="start" font-size="20" font-style="italic" fill="#8b8fa3"&gt;the long tail&lt;/text&gt;
&lt;text x="760" y="944" text-anchor="middle" font-size="21" fill="#e6e8ee"&gt;The specced surface is the outer sweep.&lt;/text&gt;
&lt;text x="760" y="972" text-anchor="middle" font-size="19" fill="#8b8fa3"&gt;The long tail curls into the center.&lt;/text&gt;
&lt;/svg&gt;
&lt;/figure&gt;
&lt;p&gt;The platforms that run most production infrastructure all have specs. AWS is the &lt;a href="https://www.statista.com/chart/18819/worldwide-market-share-of-leading-cloud-infrastructure-service-providers/"&gt;largest cloud most shops build on&lt;/a&gt;, and its spec is deep, &lt;a href="https://awsfundamentals.com/cloudformation"&gt;over 1,500 resource types&lt;/a&gt; in CloudFormation. The specced surface is the ground everyone stands on.&lt;/p&gt;</description></item><item><title>Temporal and chant saw it coming</title><link>https://lex00.github.io/posts/temporal-and-chant-saw-it-coming/</link><pubDate>Wed, 22 Jul 2026 00:00:00 +0000</pubDate><guid>https://lex00.github.io/posts/temporal-and-chant-saw-it-coming/</guid><description>&lt;p&gt;A common line drawn about AI and infrastructure: &amp;ldquo;It changes how things get written, not how they get operated.&amp;rdquo; It casts the near term as a moment when AI reshapes authoring while operations waits without an answer.&lt;/p&gt;
&lt;p&gt;This tends to come from people observing the shift rather than shipping on it, and it already reads as dated. It also has the timing backwards, treating writing and operating as a sequence when they are moving together. Temporal and chant are already built for it.&lt;/p&gt;</description></item><item><title>The long road back to cloud native</title><link>https://lex00.github.io/posts/the-long-road-back-to-native/</link><pubDate>Wed, 22 Jul 2026 00:00:00 +0000</pubDate><guid>https://lex00.github.io/posts/the-long-road-back-to-native/</guid><description>&lt;p&gt;The sensible answer about Terraform and AI goes like this: the agent writes the HCL, and Terraform keeps the parts that matter, governance and lifecycle. &lt;a href="https://wcollins.io/posts/2026/ai-through-iac-not-instead-of-it/"&gt;William Collins&lt;/a&gt; makes that case well, and I agree with more of it than you might expect. That case rests on one thing: the value it credits to Terraform lives in the tool itself.&lt;/p&gt;
&lt;p&gt;Look at what Terraform is, underneath. It takes your cloud&amp;rsquo;s native spec, the CloudFormation template or the Kubernetes object the platform already defines, and reimplements it as HCL plus a state file. It is a layer over the platform&amp;rsquo;s own API, one that &lt;a href="https://lex00.github.io/posts/honor-the-lower-layer/"&gt;stands in for the native spec instead of compiling to it&lt;/a&gt;. For a while that was a fine trade.&lt;/p&gt;</description></item><item><title>An entire industry exists to fix Terraform</title><link>https://lex00.github.io/posts/fix-terraform/</link><pubDate>Tue, 21 Jul 2026 00:00:00 +0000</pubDate><guid>https://lex00.github.io/posts/fix-terraform/</guid><description>&lt;p&gt;This is what an industry of coping mechanisms looks like. One attempt to leave Terraform&amp;rsquo;s model outright, &lt;a href="https://www.winglang.io/"&gt;Winglang&lt;/a&gt;, compiled a new language down to Terraform and shut down in 2025. When Terraform&amp;rsquo;s own license changed, the community forked the whole thing rather than let it go. The tool is too entrenched to abandon, so the market lines up to patch it.&lt;/p&gt;
&lt;figure class="diagram" role="img" aria-label="A matrix of the tools built around Terraform, with a column for whether each keeps its own state store. The fix industry: Terragrunt wraps it, TerraConstructs puts a typed object model over it, Atlantis and Spacelift and env0 run it for you, Terraform Cloud hosts the store and gives you apply, Stategraph keeps state as a dependency graph, compliance.tf adds guardrails on the modules. Every one keeps its own store, yes. Set apart, not in the industry: chant, which drives no raw API and reads the substrate, so it keeps no store of its own. State&amp;#39;s real job is to bind the name you wrote to the id the provider hands back; Terraform drives a raw API, catches that id, and makes you keep the pair, while chant compiles to the substrate&amp;#39;s own spec, which keeps the binding itself."&gt;
&lt;svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 900 456" font-family="-apple-system, Segoe UI, Helvetica, Arial, sans-serif"&gt;
 &lt;rect x="0" y="0" width="900" height="456" fill="#0d1117"/&gt;

 &lt;text x="40" y="44" font-size="22" font-weight="700" fill="#e6edf3"&gt;An industry around one tool&lt;/text&gt;
 &lt;text x="40" y="68" font-size="13" fill="#8b949e"&gt;Count them. Every one keeps a state store. chant, off on its own, keeps none.&lt;/text&gt;

 &lt;!-- column headers --&gt;
 &lt;text x="290" y="104" font-size="11" font-weight="600" fill="#6e7681" letter-spacing="0.5"&gt;DOES WHAT&lt;/text&gt;
 &lt;text x="860" y="104" font-size="11" font-weight="600" fill="#6e7681" letter-spacing="0.5" text-anchor="end"&gt;OWN STATE STORE?&lt;/text&gt;
 &lt;line x1="40" y1="114" x2="860" y2="114" stroke="#30363d" stroke-width="1"/&gt;

 &lt;!-- FIX group --&gt;
 &lt;text x="40" y="142" font-size="13" font-weight="700" fill="#e0b84a"&gt;THE FIX INDUSTRY&lt;/text&gt;
 &lt;text x="290" y="142" font-size="11.5" fill="#b0894a"&gt;keep the store, make it hurt less&lt;/text&gt;

 &lt;text x="44" y="176" font-size="13.5" font-weight="600" fill="#c9d1d9"&gt;Terragrunt&lt;/text&gt;
 &lt;text x="290" y="176" font-size="12" fill="#8b949e"&gt;wraps it&lt;/text&gt;
 &lt;text x="860" y="176" font-size="12.5" fill="#adbac7" text-anchor="end"&gt;yes&lt;/text&gt;

 &lt;text x="44" y="208" font-size="13.5" font-weight="600" fill="#c9d1d9"&gt;TerraConstructs&lt;/text&gt;
 &lt;text x="290" y="208" font-size="12" fill="#8b949e"&gt;a typed object model over it&lt;/text&gt;
 &lt;text x="860" y="208" font-size="12.5" fill="#adbac7" text-anchor="end"&gt;yes&lt;/text&gt;

 &lt;text x="44" y="240" font-size="13.5" font-weight="600" fill="#c9d1d9"&gt;Atlantis &amp;#183; Spacelift &amp;#183; env0&lt;/text&gt;
 &lt;text x="290" y="240" font-size="12" fill="#8b949e"&gt;run it for you&lt;/text&gt;
 &lt;text x="860" y="240" font-size="12.5" fill="#adbac7" text-anchor="end"&gt;yes&lt;/text&gt;

 &lt;text x="44" y="272" font-size="13.5" font-weight="600" fill="#c9d1d9"&gt;Terraform Cloud&lt;/text&gt;
 &lt;text x="290" y="272" font-size="12" fill="#8b949e"&gt;hosts the store, gives you apply&lt;/text&gt;
 &lt;text x="860" y="272" font-size="12.5" fill="#adbac7" text-anchor="end"&gt;yes&lt;/text&gt;

 &lt;text x="44" y="304" font-size="13.5" font-weight="600" fill="#c9d1d9"&gt;Stategraph&lt;/text&gt;
 &lt;text x="290" y="304" font-size="12" fill="#8b949e"&gt;state as a dependency graph&lt;/text&gt;
 &lt;text x="860" y="304" font-size="12.5" fill="#adbac7" text-anchor="end"&gt;yes&lt;/text&gt;

 &lt;text x="44" y="336" font-size="13.5" font-weight="600" fill="#c9d1d9"&gt;compliance.tf&lt;/text&gt;
 &lt;text x="290" y="336" font-size="12" fill="#8b949e"&gt;guardrails on the modules&lt;/text&gt;
 &lt;text x="860" y="336" font-size="12.5" fill="#adbac7" text-anchor="end"&gt;yes&lt;/text&gt;

 &lt;!-- chant, set apart --&gt;
 &lt;line x1="40" y1="362" x2="860" y2="362" stroke="#21262d" stroke-width="1" stroke-dasharray="3 4"/&gt;
 &lt;text x="40" y="388" font-size="11" font-weight="600" fill="#6e7681" letter-spacing="0.5"&gt;NOT IN THE INDUSTRY&lt;/text&gt;
 &lt;rect x="34" y="400" width="830" height="42" rx="9" fill="#1a9850" fill-opacity="0.14" stroke="#1a9850" stroke-opacity="0.9" stroke-width="1.5"/&gt;
 &lt;text x="52" y="426" font-size="15" font-weight="700" fill="#7ee787"&gt;chant&lt;/text&gt;
 &lt;text x="290" y="426" font-size="12" fill="#adbac7"&gt;drives no raw API, reads the substrate&lt;/text&gt;
 &lt;text x="860" y="426" font-size="14" font-weight="700" fill="#7ee787" text-anchor="end"&gt;none&lt;/text&gt;
&lt;/svg&gt;

&lt;/figure&gt;
&lt;p&gt;The last column is the whole story. State&amp;rsquo;s real job is to bind the name you wrote, &lt;code&gt;MyResource&lt;/code&gt;, to the opaque id the provider hands back, so the next run knows the two are the same thing. Terraform drives a raw API, catches that id, and makes you hold on to it. chant drives no raw API. It compiles to the platform&amp;rsquo;s own spec, which keeps the binding itself, so there is no pair to store.&lt;/p&gt;</description></item><item><title>Configuration as code, and as data</title><link>https://lex00.github.io/posts/code-as-config-config-as-data/</link><pubDate>Mon, 20 Jul 2026 00:00:00 +0000</pubDate><guid>https://lex00.github.io/posts/code-as-config-config-as-data/</guid><description>&lt;p&gt;&lt;a href="https://medium.com/@bgrant0607"&gt;Brian Grant&lt;/a&gt; coined the &lt;a href="https://kube.fm/krm-brian"&gt;Kubernetes Resource Model&lt;/a&gt; and argues that configuration should be data, not a program you run to find out what it is. chant agrees, and most of the industry is still catching up to him.&lt;/p&gt;
&lt;p&gt;His case is simple: declarative configuration is data. It is separated from the code that transforms it. This is a huge part of what makes Kubernetes manageable.&lt;/p&gt;
&lt;h1 id="chant-is-configuration-as-data"&gt;chant is configuration as data&lt;/h1&gt;
&lt;p&gt;chant compiles a typed source to the platform&amp;rsquo;s own spec and hands that spec back untouched.&lt;/p&gt;</description></item><item><title>Honor the lower layer</title><link>https://lex00.github.io/posts/honor-the-lower-layer/</link><pubDate>Sun, 19 Jul 2026 00:00:00 +0000</pubDate><guid>https://lex00.github.io/posts/honor-the-lower-layer/</guid><description>&lt;p&gt;This post makes one narrow claim, one you should check rather than take on faith.&lt;/p&gt;
&lt;p&gt;Every tool sits on a lower layer. For infrastructure it is a cloud&amp;rsquo;s native spec or a Kubernetes API. For a programming language it is the machine itself. Good abstractions honor that layer, while poor ones reimplement it with something that only pretends to match, up until the pretense breaks.&lt;/p&gt;
&lt;p&gt;Two people in two fields, &lt;a href="https://www.linkedin.com/in/ghohpe"&gt;Gregor Hohpe&lt;/a&gt; in software architecture and &lt;a href="https://www.linkedin.com/in/adamch/"&gt;Adam Chlipala&lt;/a&gt; in formal verification, describe that same failure and the same fix.&lt;/p&gt;</description></item><item><title>A lifecycle needs an orchestrator</title><link>https://lex00.github.io/posts/a-lifecycle-needs-an-orchestrator/</link><pubDate>Fri, 17 Jul 2026 00:00:00 +0000</pubDate><guid>https://lex00.github.io/posts/a-lifecycle-needs-an-orchestrator/</guid><description>&lt;p&gt;Terraform 1.14 shipped Actions, its biggest language change in years. An Action fires a provider operation, a Lambda invoke or a cache invalidation, on a resource&amp;rsquo;s create, update, or destroy. The imperative work that used to hide in &lt;code&gt;null_resource&lt;/code&gt; finally has a place to sit.&lt;/p&gt;
&lt;p&gt;Then you ask what runs it, and the answer is nothing. No typed input, no retry, no timeout, no gate, no record it ran. An Action is a trigger with no executor, and every one of those gaps is that same missing piece.&lt;/p&gt;</description></item><item><title>Policy belongs left of the platform</title><link>https://lex00.github.io/posts/policy-belongs-left-of-the-platform/</link><pubDate>Fri, 17 Jul 2026 00:00:00 +0000</pubDate><guid>https://lex00.github.io/posts/policy-belongs-left-of-the-platform/</guid><description>&lt;p&gt;Everyone is shifting policy left. HashiCorp just shipped tfpolicy, a policy-as-code framework in HCL, and it moves the catch earlier than Sentinel ever did. Provider and module rules run pre-plan before a download, resource rules run at plan, and computed values get checked at apply. One language does all of it, so the second one that Sentinel and OPA made you learn is gone.&lt;/p&gt;
&lt;p&gt;It still runs at the platform. tfpolicy evaluates inside HCP Terraform, against a plan, with credentials. Its rules are HCL over &lt;code&gt;attrs&lt;/code&gt;, a dynamic bag nothing type-checks. &lt;code&gt;attrs.encryption_settings_collection[0].enabled&lt;/code&gt; is a string path you either get right or find out about at evaluation time, in the run, not in your editor.&lt;/p&gt;</description></item><item><title>Your infra database is a road to hell</title><link>https://lex00.github.io/posts/your-infra-database-is-a-road-to-hell/</link><pubDate>Fri, 17 Jul 2026 00:00:00 +0000</pubDate><guid>https://lex00.github.io/posts/your-infra-database-is-a-road-to-hell/</guid><description>&lt;p&gt;The authoritative model Terraform made famous has always been a poor fit for teams just trying to automate a little infra. The state file is only its most visible cost. Give up the model and three questions decide the tool: how the truth is represented, where it lives, and what lifecycle runs around it. &lt;a href="https://confighub.com/"&gt;ConfigHub&lt;/a&gt; and &lt;a href="https://github.com/platform-engineering-labs/formae"&gt;formae&lt;/a&gt; are already past it, and &lt;a href="https://intentius.io/chant/"&gt;chant&lt;/a&gt; answers the same three again.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Representation.&lt;/strong&gt; ConfigHub makes the truth data in a store. formae makes it Pkl. chant makes it typed TypeScript that is the spec itself.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Location.&lt;/strong&gt; ConfigHub puts the truth in a database. formae pushes it into the source code and reconciles the cloud back to it. chant leaves it in the live system, where it already is.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lifecycle.&lt;/strong&gt; ConfigHub builds one around its store. formae builds one that pulls reality into code. chant hands the lifecycle to you, dialed per environment.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ownership.&lt;/strong&gt; Terraform ties it to state. ConfigHub delegates it to live markers in ArgoCD and Crossplane, which is right. chant reads it straight off the resource, no store in the loop.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Verdict.&lt;/strong&gt; Three tools past the authoritative model, and one that also refuses to own you: typed source you already write, truth left live, artifacts that outlive the tool.&lt;/li&gt;
&lt;/ul&gt;
&lt;figure class="diagram" role="img" aria-label="Three panels showing where each tool keeps the truth. ConfigHub in a database, formae in the source code with a reconcile loop, chant in the live system as typed TypeScript. Above them, the discarded authoritative model where state, truth, and ownership are one locked box."&gt;
&lt;svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 900 560" font-family="-apple-system, Segoe UI, Helvetica, Arial, sans-serif"&gt;
 &lt;defs&gt;
 &lt;marker id="loopblue" markerWidth="9" markerHeight="9" refX="4" refY="4" orient="auto" markerUnits="strokeWidth"&gt;
 &lt;path d="M0,0 L6,4 L0,8 Z" fill="#58a6ff"/&gt;
 &lt;/marker&gt;
 &lt;/defs&gt;

 &lt;rect x="0" y="0" width="900" height="560" fill="#0d1117"/&gt;

 &lt;text x="40" y="44" font-size="22" font-weight="700" fill="#e6edf3"&gt;Three homes for the truth&lt;/text&gt;
 &lt;text x="40" y="68" font-size="13" fill="#8b949e"&gt;The authoritative model is gone. Where each tool keeps the truth now.&lt;/text&gt;

 &lt;!-- discarded model --&gt;
 &lt;rect x="298" y="92" width="304" height="52" rx="8" fill="#161b22" stroke="#6e7681" stroke-width="1.5" stroke-dasharray="5 4"/&gt;
 &lt;rect x="320" y="112" width="15" height="12" rx="2" fill="none" stroke="#6e7681" stroke-width="1.5"/&gt;
 &lt;path d="M323,112 a4.5,4.5 0 0 1 9,0" fill="none" stroke="#6e7681" stroke-width="1.5"/&gt;
 &lt;text x="470" y="114" font-size="13" font-weight="600" fill="#adbac7" text-anchor="middle"&gt;state = truth = ownership&lt;/text&gt;
 &lt;text x="470" y="132" font-size="11" fill="#6e7681" text-anchor="middle"&gt;Terraform · Pulumi&lt;/text&gt;
 &lt;text x="450" y="164" font-size="11" fill="#6e7681" text-anchor="middle" font-style="italic"&gt;left behind by all three&lt;/text&gt;

 &lt;line x1="60" y1="192" x2="840" y2="192" stroke="#30363d" stroke-width="1"/&gt;
 &lt;text x="450" y="222" font-size="13" fill="#c9d1d9" text-anchor="middle"&gt;the truth now lives in…&lt;/text&gt;

 &lt;!-- ConfigHub --&gt;
 &lt;rect x="40" y="244" width="250" height="286" rx="10" fill="#161b22" stroke="#e0b84a" stroke-width="1.5"/&gt;
 &lt;ellipse cx="165" cy="280" rx="38" ry="10" fill="#1b2230" stroke="#e0b84a" stroke-width="1.8"/&gt;
 &lt;line x1="127" y1="280" x2="127" y2="316" stroke="#e0b84a" stroke-width="1.8"/&gt;
 &lt;line x1="203" y1="280" x2="203" y2="316" stroke="#e0b84a" stroke-width="1.8"/&gt;
 &lt;path d="M127,316 A38,10 0 0 0 203,316" fill="none" stroke="#e0b84a" stroke-width="1.8"/&gt;
 &lt;path d="M127,294 A38,10 0 0 0 203,294" fill="none" stroke="#e0b84a" stroke-width="1" opacity="0.5"/&gt;
 &lt;path d="M127,305 A38,10 0 0 0 203,305" fill="none" stroke="#e0b84a" stroke-width="1" opacity="0.5"/&gt;
 &lt;text x="165" y="372" font-size="17" font-weight="700" fill="#e0b84a" text-anchor="middle"&gt;ConfigHub&lt;/text&gt;
 &lt;text x="165" y="398" font-size="12.5" fill="#c9d1d9" text-anchor="middle"&gt;truth = data in a store&lt;/text&gt;
 &lt;text x="165" y="418" font-size="12.5" fill="#c9d1d9" text-anchor="middle"&gt;you author in the store&lt;/text&gt;
 &lt;line x1="70" y1="438" x2="260" y2="438" stroke="#30363d" stroke-width="1"/&gt;
 &lt;text x="165" y="462" font-size="12" fill="#e0b84a" text-anchor="middle" opacity="0.85"&gt;requires a database&lt;/text&gt;

 &lt;!-- formae --&gt;
 &lt;rect x="325" y="244" width="250" height="286" rx="10" fill="#161b22" stroke="#58a6ff" stroke-width="1.5"/&gt;
 &lt;text x="450" y="298" font-size="42" font-weight="700" fill="#58a6ff" text-anchor="middle"&gt;{ }&lt;/text&gt;
 &lt;path d="M450,311 a13,13 0 1 1 -9,3.5" fill="none" stroke="#58a6ff" stroke-width="2" marker-end="url(#loopblue)"/&gt;
 &lt;text x="450" y="372" font-size="17" font-weight="700" fill="#58a6ff" text-anchor="middle"&gt;formae&lt;/text&gt;
 &lt;text x="450" y="398" font-size="12.5" fill="#c9d1d9" text-anchor="middle"&gt;truth = the source code&lt;/text&gt;
 &lt;text x="450" y="418" font-size="12.5" fill="#c9d1d9" text-anchor="middle"&gt;cloud reconciled back to code&lt;/text&gt;
 &lt;line x1="355" y1="438" x2="545" y2="438" stroke="#30363d" stroke-width="1"/&gt;
 &lt;text x="450" y="462" font-size="12" fill="#58a6ff" text-anchor="middle" opacity="0.85"&gt;right inversion, wrong language&lt;/text&gt;

 &lt;!-- chant --&gt;
 &lt;rect x="610" y="244" width="250" height="286" rx="10" fill="#1a9850" opacity="0.08"/&gt;
 &lt;rect x="610" y="244" width="250" height="286" rx="10" fill="none" stroke="#1a9850" stroke-width="2.5"/&gt;
 &lt;path d="M712,306 a13,13 0 0 1 0,-24 a16,16 0 0 1 30,-4 a12,12 0 0 1 15,6 a12,12 0 0 1 -3,22 z" fill="#12261a" stroke="#1a9850" stroke-width="2"/&gt;
 &lt;text x="735" y="296" font-size="13" font-weight="700" fill="#68d391" text-anchor="middle"&gt;{ TS }&lt;/text&gt;
 &lt;text x="735" y="372" font-size="17" font-weight="700" fill="#68d391" text-anchor="middle"&gt;chant&lt;/text&gt;
 &lt;text x="735" y="398" font-size="12.5" fill="#d6f5e2" text-anchor="middle"&gt;truth = the live system&lt;/text&gt;
 &lt;text x="735" y="418" font-size="12.5" fill="#d6f5e2" text-anchor="middle"&gt;typed source in, native out&lt;/text&gt;
 &lt;line x1="640" y1="438" x2="830" y2="438" stroke="#1f4d34" stroke-width="1"/&gt;
 &lt;text x="735" y="462" font-size="12" fill="#68d391" text-anchor="middle"&gt;no database, nothing to unwind&lt;/text&gt;
&lt;/svg&gt;

&lt;/figure&gt;
&lt;h2 id="confighub-owns-all-three"&gt;ConfigHub owns all three&lt;/h2&gt;
&lt;p&gt;ConfigHub replaces the file with a database, and the database is the truth. You author in it through an API. It actuates from it. Brian Grant is right that configuration is data and that Git is a poor place to keep it, and the product follows honestly from that.&lt;/p&gt;</description></item><item><title>A release is a compile target</title><link>https://lex00.github.io/posts/a-release-is-a-compile-target/</link><pubDate>Tue, 14 Jul 2026 00:00:00 +0000</pubDate><guid>https://lex00.github.io/posts/a-release-is-a-compile-target/</guid><description>&lt;p&gt;Call something a compile target and you have said two things about it. It can be correct by construction, and it is cheap to produce. A compiler checks the output before it emits it, and it emits it from a description shorter than the output itself. That is the whole reason to have one.&lt;/p&gt;
&lt;p&gt;Say it about a release and both claims carry. The deploy can be correct before it runs, and adding one costs a declaration instead of a pipeline.&lt;/p&gt;</description></item><item><title>The apply verb you only get on Kubernetes</title><link>https://lex00.github.io/posts/the-apply-verb-you-only-get-on-kubernetes/</link><pubDate>Mon, 06 Jul 2026 00:00:00 +0000</pubDate><guid>https://lex00.github.io/posts/the-apply-verb-you-only-get-on-kubernetes/</guid><description>&lt;p&gt;Kubernetes made something uniform that people forget was ever a choice. Every service deploys the same way. A manifest describes the desired state, &lt;code&gt;kubectl apply&lt;/code&gt; hands it over, and a controller makes it real. Because the verb is shared, the CI around it is shared too. A platform team writes one pipeline and a hundred services ride it, since from the pipeline&amp;rsquo;s point of view they are all the same operation.&lt;/p&gt;</description></item><item><title>Governance without the state file</title><link>https://lex00.github.io/posts/governance-without-the-state-file/</link><pubDate>Sat, 20 Jun 2026 00:00:00 +0000</pubDate><guid>https://lex00.github.io/posts/governance-without-the-state-file/</guid><description>&lt;p&gt;How easily can you prove that all your repositories have aligned configuration according to policy?&lt;/p&gt;
&lt;p&gt;Governance is easy when it comes to things people rarely touch. I&amp;rsquo;ll bet a lot of you reading this manually tune your repo settings, and have already thought about how you might make them more consistent.&lt;/p&gt;
&lt;h2 id="why-policy-drifts"&gt;Why policy drifts&lt;/h2&gt;
&lt;p&gt;Platform settings are stateful and the typical case is that nothing reconciles them. You set branch protection once. After that it is a value in a database that any admin can change.&lt;/p&gt;</description></item><item><title>A TypeScript compiler for Kubernetes manifests</title><link>https://lex00.github.io/posts/a-typescript-compiler-for-kubernetes-manifests/</link><pubDate>Thu, 18 Jun 2026 00:00:00 +0000</pubDate><guid>https://lex00.github.io/posts/a-typescript-compiler-for-kubernetes-manifests/</guid><description>&lt;p&gt;A GitOps pipeline on Kubernetes is full of tools. Reconcilers like Flux or Argo watch git and converge the cluster. Drift gets detected and alarmed while policy engines gate what reaches the cluster at every stage.&lt;/p&gt;
&lt;p&gt;The least guarded stage is the one where the manifests get written. YAML gets patched with Kustomize and templated with Helm, then goes unchecked for meaning until the reconciler tries to apply it.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://intentius.io/chant/"&gt;chant&lt;/a&gt; is a compiler for that layer. Typed TypeScript goes in and native Kubernetes YAML comes out. The build type checks and semantic lints and synthesizes deterministically, then stops and hands a standard manifest to the existing deploy path.&lt;/p&gt;</description></item><item><title>The far-left IaC tool</title><link>https://lex00.github.io/posts/the-far-left-iac-tool/</link><pubDate>Wed, 03 Jun 2026 00:00:00 +0000</pubDate><guid>https://lex00.github.io/posts/the-far-left-iac-tool/</guid><description>&lt;p&gt;Everyone is shifting left. It&amp;rsquo;s the safest opinion in infrastructure, and most tools honor it by shifting left exactly one notch and calling it a platform.&lt;/p&gt;
&lt;p&gt;Terraform shifted left with &lt;code&gt;plan&lt;/code&gt;, Bicep with &lt;code&gt;what-if&lt;/code&gt;. Same idea, see the change before you apply it. Both are real improvements, and both still wait until you&amp;rsquo;re talking to the cloud to tell you something is wrong. That&amp;rsquo;s the centrist position. It&amp;rsquo;s good, but it isn&amp;rsquo;t the leftmost spot on the line.&lt;/p&gt;</description></item><item><title>TypeScript vs Pkl for IaC</title><link>https://lex00.github.io/posts/typescript-vs-pkl-for-iac/</link><pubDate>Wed, 27 May 2026 00:00:00 +0000</pubDate><guid>https://lex00.github.io/posts/typescript-vs-pkl-for-iac/</guid><description>&lt;p&gt;Two tools have made the same uncommon choice. &lt;a href="https://intentius.io/chant/"&gt;chant&lt;/a&gt; and &lt;a href="https://github.com/platform-engineering-labs/formae"&gt;formae&lt;/a&gt; both refuse the authoritative state file. Most infrastructure tools keep one. These two do not. That shared move is the right place to start, because it is the right move.&lt;/p&gt;
&lt;h2 id="the-state-file-was-never-the-part-that-matters"&gt;The state file was never the part that matters&lt;/h2&gt;
&lt;p&gt;An authoritative state file is a flat file doing a database&amp;rsquo;s job. It needs a lock on every change. It holds secrets because the tool needs them to diff. It can corrupt and take a deploy down. Teams carry all of that because they believe state is essential. What is actually essential is governance. A known change before apply. An audit trail. A limit on blast radius. State was one way to get those. It was never the only way.&lt;/p&gt;</description></item><item><title>Which infrastructure tool actually keeps the spec?</title><link>https://lex00.github.io/posts/which-tool-keeps-the-spec/</link><pubDate>Wed, 27 May 2026 00:00:00 +0000</pubDate><guid>https://lex00.github.io/posts/which-tool-keeps-the-spec/</guid><description>&lt;p&gt;&lt;em&gt;In the IaC world, who is truly spec native?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Most infrastructure tools put a layer between you and the target spec. The layer is the product. It owns state, deployment, and a model of your cloud that is not quite the cloud&amp;rsquo;s own model. &lt;a href="https://intentius.io/chant/"&gt;Chant&lt;/a&gt; makes a different choice. Its types come from the target spec. Its output is the target spec. Nothing chant specific survives in the artifact.&lt;/p&gt;
&lt;p&gt;This post explains that choice. It also shows where Terraform, AWS CDK, and Pulumi drift from the spec, and what staying close to the spec buys you.&lt;/p&gt;</description></item><item><title>Governance is what IaC depends on</title><link>https://lex00.github.io/posts/governance-is-load-bearing/</link><pubDate>Mon, 25 May 2026 00:00:00 +0000</pubDate><guid>https://lex00.github.io/posts/governance-is-load-bearing/</guid><description>&lt;p&gt;State is essential. Anyone who has run infrastructure past a toy project knows this. &lt;a href="https://wcollins.io/posts/2026/ai-through-iac-not-instead-of-it/"&gt;William Collins&lt;/a&gt; makes the case for AI through IaC rather than instead of it, and I agree with most of it. My argument is narrower. Essential is not the same as authoritative. Almost everything you value about state is essential without being authoritative.&lt;/p&gt;
&lt;h2 id="what-the-file-actually-costs"&gt;What the file actually costs&lt;/h2&gt;
&lt;p&gt;Start with what a state file charges you. A global mutex on every apply. An all-or-nothing changeset. Secrets sitting in the file because the tool needs them to diff. A corruption surface that can take a stack down. None of that is the language. None of it is the providers. It is a flat file doing the work of a database, and the database has no tooling.&lt;/p&gt;</description></item><item><title>The consolidation problem</title><link>https://lex00.github.io/posts/the-consolidation-problem/</link><pubDate>Sat, 28 Mar 2026 00:00:00 +0000</pubDate><guid>https://lex00.github.io/posts/the-consolidation-problem/</guid><description>&lt;p&gt;The pull request didn&amp;rsquo;t start as a bureaucratic institution. It started because someone needed a way to propose changes to code they didn&amp;rsquo;t own. The only mechanism for that was to ask the owner. The queue, the approval chain, the blocked deploy: none of it was planned. It followed from that one fact.&lt;/p&gt;
&lt;p&gt;The person holding the key usually didn&amp;rsquo;t ask for the job. A senior engineer merges things because she has the access and nobody else does. She goes on vacation and the team waits. She burns out and the PRs pile up. She never wanted to be a gatekeeper. The tool made her one.&lt;/p&gt;</description></item><item><title>Infrastructure deserves a compiler</title><link>https://lex00.github.io/posts/infrastructure-deserves-a-compiler/</link><pubDate>Mon, 23 Feb 2026 00:00:00 +0000</pubDate><guid>https://lex00.github.io/posts/infrastructure-deserves-a-compiler/</guid><description>&lt;p&gt;Every IaC tool tries to own the full lifecycle. Provisioning, state management, drift detection, rollback. The synthesis step got bundled in with the rest. Turning source code into deployable output is a compilation problem. It deserves to be treated like one.&lt;/p&gt;
&lt;h2 id="what-bundling-synthesis-costs-you"&gt;What bundling synthesis costs you&lt;/h2&gt;
&lt;p&gt;When synthesis is embedded in a provisioning tool, it inherits that tool&amp;rsquo;s constraints. You get the type system the tool provides. You get the validation the tool exposes. You lint what the tool lets you lint.&lt;/p&gt;</description></item></channel></rss>