<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Jean-Luc Martel</title>
    <description>The latest articles on DEV Community by Jean-Luc Martel (@jlmartel).</description>
    <link>https://dev.to/jlmartel</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4061410%2Fc407a2f0-c9db-4796-bcf2-43f744536ee6.jpg</url>
      <title>DEV Community: Jean-Luc Martel</title>
      <link>https://dev.to/jlmartel</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jlmartel"/>
    <language>en</language>
    <item>
      <title>A zero-disruption PodDisruptionBudget can block an AKS upgrade</title>
      <dc:creator>Jean-Luc Martel</dc:creator>
      <pubDate>Thu, 08 Oct 2026 04:06:50 +0000</pubDate>
      <link>https://dev.to/jlmartel/a-zero-disruption-poddisruptionbudget-can-block-an-aks-upgrade-18h5</link>
      <guid>https://dev.to/jlmartel/a-zero-disruption-poddisruptionbudget-can-block-an-aks-upgrade-18h5</guid>
      <description>&lt;p&gt;Your AKS cluster upgrade is stuck.&lt;/p&gt;

&lt;p&gt;The control plane is waiting for a node to drain. The node is waiting for a pod to terminate. The pod is refusing to move.&lt;/p&gt;

&lt;p&gt;Look at the logs. The workload has a PodDisruptionBudget that allows exactly zero disruptions.&lt;/p&gt;

&lt;p&gt;It is doing exactly what it was told to do. Protect the application at all costs. Even if it means halting the cluster upgrade.&lt;/p&gt;

&lt;p&gt;To upgrade a node, AKS has to drain it. It cordons the node and evicts the pods.&lt;/p&gt;

&lt;p&gt;But the eviction process respects disruption budgets.&lt;/p&gt;

&lt;p&gt;If your deployment has three replicas, and your budget dictates that three must remain available, the eviction fails. The node stays tainted. The upgrade stalls.&lt;/p&gt;

&lt;p&gt;You didn't just configure high availability. You configured a deadlock.&lt;/p&gt;

&lt;p&gt;Replica headroom isn't just a best practice for scaling. It is the physical space required for the control plane to do maintenance.&lt;/p&gt;

&lt;p&gt;Before your next maintenance window, look at your math.&lt;/p&gt;

&lt;p&gt;Check your &lt;code&gt;minAvailable&lt;/code&gt; or &lt;code&gt;maxUnavailable&lt;/code&gt; settings against the actual number of running replicas. &lt;/p&gt;

&lt;p&gt;If you use &lt;code&gt;minAvailable&lt;/code&gt; with a percentage, remember that Kubernetes rounds up. A setting of 100% means zero disruptions allowed. A setting of 90% with three replicas rounds up to three.&lt;/p&gt;

&lt;p&gt;You have to leave room for the scheduler to breathe. Configure these values deliberately, not just to pass a compliance check.&lt;/p&gt;

&lt;p&gt;High availability means surviving a failure. It shouldn't mean blocking your own operations team.&lt;/p&gt;

&lt;p&gt;Your availability policy guarantees the app survives a zone failure. But has anyone tested whether it survives routine maintenance?&lt;/p&gt;

&lt;p&gt;If your zero-disruption configuration blocks your upgrade pipeline, you haven't built a resilient system.&lt;/p&gt;

&lt;p&gt;You have built a hostage situation.&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>aws</category>
      <category>cloud</category>
      <category>devops</category>
    </item>
    <item>
      <title>I rebuilt four dead systems with AI. The failures all landed in the same place.</title>
      <dc:creator>Jean-Luc Martel</dc:creator>
      <pubDate>Thu, 24 Sep 2026 16:55:00 +0000</pubDate>
      <link>https://dev.to/jlmartel/i-rebuilt-four-dead-systems-with-ai-the-failures-all-landed-in-the-same-place-38pa</link>
      <guid>https://dev.to/jlmartel/i-rebuilt-four-dead-systems-with-ai-the-failures-all-landed-in-the-same-place-38pa</guid>
      <description>&lt;p&gt;Four reconstructions, four kinds of missing documentation, and the defects landed in the same place every time.&lt;/p&gt;

&lt;p&gt;In HAL/S it was the characters the scanner destroyed. In the Nautilus simulator it was the parameters Verne never wrote down. In Wikicarta it was the desktop window no headless harness can open. In the compressor it was the part of the input space the corpus never sampled.&lt;/p&gt;

&lt;p&gt;Different projects, different languages, different failure symptoms. One shape: &lt;strong&gt;the defects clustered wherever no automated check could reach, and in every case the code looked fine.&lt;/strong&gt; Tests green, types satisfied, output plausible.&lt;/p&gt;

&lt;h2&gt;
  
  
  What was actually being varied
&lt;/h2&gt;

&lt;p&gt;These weren't four projects that happened to be about old software. They were one experiment with a controlled variable: &lt;em&gt;how degraded is the source of truth the model works from, and can it be caught being wrong?&lt;/em&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;arm&lt;/th&gt;
&lt;th&gt;source of truth&lt;/th&gt;
&lt;th&gt;oracle&lt;/th&gt;
&lt;th&gt;outcome&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/singular-state/space-shuttle-sdk" rel="noopener noreferrer"&gt;HAL/S&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;degraded formal spec + preserved code&lt;/td&gt;
&lt;td&gt;strong, independent&lt;/td&gt;
&lt;td&gt;faithful reconstruction; 12/12 preserved programs run&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/singular-state/nautilus-sim" rel="noopener noreferrer"&gt;Nautilus&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;a novel&lt;/td&gt;
&lt;td&gt;none — one was built&lt;/td&gt;
&lt;td&gt;5 findings; the legend fails on every axis&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/singular-state/wikicarta" rel="noopener noreferrer"&gt;Wikicarta&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;memory of a product&lt;/td&gt;
&lt;td&gt;none — human judgement&lt;/td&gt;
&lt;td&gt;shippable app; every defect at the runtime seam&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/singular-state/compressor" rel="noopener noreferrer"&gt;compressor&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;behaviour only, key sealed&lt;/td&gt;
&lt;td&gt;strong, opened after freeze&lt;/td&gt;
&lt;td&gt;decoder 100%, encoder 8.3%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The intuition going in was that performance would degrade smoothly as the source got worse. It didn't. Something else predicted the results, and it cut across all four.&lt;/p&gt;

&lt;h2&gt;
  
  
  Determined beats hard
&lt;/h2&gt;

&lt;p&gt;The reconstruction quality tracked whether &lt;strong&gt;the available evidence determines the answer&lt;/strong&gt; — not how difficult the task was.&lt;/p&gt;

&lt;p&gt;The compressor makes this measurable, because both halves ran under identical conditions. The decoder recovered the bitstream format at 100%, because a format is one-way determined: if you want to decode the stream, exactly one answer works. The encoder scored 8.3% on the same format, because its heuristics — match-finder strategy, tie-breaking, greedy versus lazy — are &lt;em&gt;choices&lt;/em&gt; that leave no trace in the decompressed bytes. Same model family, same oracle, same week. A 12× gap, entirely explained by whether the evidence pinned the answer.&lt;/p&gt;

&lt;p&gt;The other three say the same thing in their own terms:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;HAL/S.&lt;/strong&gt; The 485 grammar productions were determined by the page images, and the reconstruction got them. The characters the scan physically destroyed were determined by nothing, and no amount of model capability recovers them. That limit is information-theoretic. Better OCR narrows it and never closes it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Nautilus.&lt;/strong&gt; The physics is determined; the equations produce the same crush depth for anyone. The parameters Verne omitted are determined by nothing, so submerged endurance ranges across 6 to 211 hours — a 35× spread — and battery capacity across 100×. Those spreads aren't noise around a finding. They &lt;em&gt;are&lt;/em&gt; the finding.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Wikicarta.&lt;/strong&gt; Parsing, backoff, cache naming and database ordering are determined by their inputs, and compiled correct on the first or second attempt, consistently. Whether the category wheel feels like Encarta is determined by nothing you can write down, and stayed a human call from start to finish.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The practical version: before handing a legacy task to a model, ask whether the evidence you have actually pins the answer. If it does, expect the model to find it and build a cheap mechanical check to confirm. If it doesn't, expect a confident, plausible, unmarked invention — and note that the model will not tell you which mode it's in, because from the inside they feel identical.&lt;/p&gt;

&lt;h2&gt;
  
  
  A strong oracle is not the protection you think
&lt;/h2&gt;

&lt;p&gt;The compressor was built to demonstrate that a strong oracle masks confabulation. It mostly refuted that.&lt;/p&gt;

&lt;p&gt;The reconstruction's central error — assigning Huffman code lengths by symbol index rather than in heap-extraction order — failed the byte-match test loudly. The oracle caught it. What the oracle &lt;em&gt;did&lt;/em&gt; hide were two mechanisms the corpus never triggered: a block-splitting path that needs inputs larger than 8 KiB to fire, and a match-finder chain cap that needs input more self-similar than anything tested.&lt;/p&gt;

&lt;p&gt;So the masking risk is not a property of the oracle's strength. &lt;strong&gt;It's a property of the input space you sampled.&lt;/strong&gt; A strong checker over a narrow corpus hides precisely the mechanisms your corpus never exercises, and hides them silently, because everything it can see is green.&lt;/p&gt;

&lt;p&gt;Strengthening the checker does nothing for this. Widening the corpus does.&lt;/p&gt;

&lt;p&gt;That generalises past compression. It's the same failure as a test suite with excellent coverage of the paths anyone thought to write a test for.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the human actually contributed
&lt;/h2&gt;

&lt;p&gt;I expected to spend supervision effort reviewing code. Across all four projects, almost none of it went there. The load-bearing human contributions were:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;HAL/S&lt;/strong&gt; — deciding &lt;em&gt;not&lt;/em&gt; to vote between OCR engines, and then reading 485 grammar productions against page images by eye.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Nautilus&lt;/strong&gt; — signing the invariants and making them append-only, so the model could patch the physics but was structurally unable to weaken the checks that judge it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Wikicarta&lt;/strong&gt; — being the runtime. Clicking the button in the real window, on the real WebKit build, where the blocking dialog freeze and the cross-realm &lt;code&gt;instanceof&lt;/code&gt; failure lived.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;compressor&lt;/strong&gt; — holding the seal. Not reading the answer key until the reconstruction was frozen at a tag.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Two categories, and neither is code review. One is &lt;strong&gt;supplying what no code can check&lt;/strong&gt; — an eye on a page image, a hand on a mouse. The other is &lt;strong&gt;designing the checks that are possible&lt;/strong&gt; and then putting them structurally out of the model's reach.&lt;/p&gt;

&lt;p&gt;The OCR decision is the sharpest of the four, because it's a judgement call that separates a good result from a worthless one that looks identical. Running three OCR engines and taking the majority is the obvious move and it is wrong: the errors are correlated, so a vote launders error rather than cancelling it, and no fusion can recover a character that no engine produced. Survivable in prose, fatal in a grammar where the metacharacters are the content. Take the vote and you get a clean, plausible, silently corrupt grammar — and every downstream artifact inherits it.&lt;/p&gt;

&lt;p&gt;The Nautilus invariant signing is the most reusable. Twelve invariants live in version control with a manifest checksum only a human re-signs. When the fuzzer finds a violation, the repair workflow requires patching the core and forbids touching the invariant. An agent optimising against a check it can also edit is not being checked.&lt;/p&gt;

&lt;h2&gt;
  
  
  Build the oracle before the artifact
&lt;/h2&gt;

&lt;p&gt;Ranked by how much verification apparatus existed before the real work started, the four projects come out in the same order as how much I trust their conclusions.&lt;/p&gt;

&lt;p&gt;Nautilus had determinism, golden-stream replay and malformed-input fuzzing green in its check harness &lt;strong&gt;before a single equation was written&lt;/strong&gt;, plus a frozen protocol and a rule that every spec parameter traces to either a sourced claim or a documented gap range. Its numbers are the most defensible in the series. The compressor's seal, cold-recall protocol, freeze tag and grading harness are most of that repository; the reconstruction is the small part. HAL/S inherited an independent interpreter, which is a luxury and which is why it is the easiest arm.&lt;/p&gt;

&lt;p&gt;Wikicarta had none of this available, and it shows — its conclusions are qualitative, argued from patterns across features rather than measured. They're still the most immediately useful findings in the series, and they're the least provable. Both things are true because of the same missing oracle.&lt;/p&gt;

&lt;p&gt;There's a specific trap worth naming. A verification harness that finds nothing is indistinguishable from a broken one. Nautilus's 24-hour soak ran 879,643 ticks and found zero invariant violations, which is only meaningful because the harness was first validated against a deliberately poisoned invariant — which it caught, minimised from seven commands to two, and packaged. Test the test.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three results that went the wrong way
&lt;/h2&gt;

&lt;p&gt;A series that only reports confirmations is a demo reel. These four produced three clean refutations, and they were the most informative outputs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The compressor predicted the classic overfitting curve — strong on trained data, weak on held-out. It came out inverted, 8% trained against 71% held-out, because the split tracked &lt;em&gt;difficulty&lt;/em&gt; rather than seen-versus-unseen.&lt;/li&gt;
&lt;li&gt;It also predicted the oracle would mask confabulation. The oracle caught the main error; a narrow corpus hid the rest.&lt;/li&gt;
&lt;li&gt;Nautilus's fuzzer was built to find physics exploits. It found none. The only finding in the whole loop was a flaw in the experiment design — the genetic algorithm had been optimising survival rather than performance, because the controller pinned its own objectives.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each of those changed the conclusion. None would have surfaced from reasoning about the problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where this doesn't reach
&lt;/h2&gt;

&lt;p&gt;Four projects, one operator, no control group. There is no human-only reconstruction to compare against, so nothing here says AI was faster or better than the alternative — only what it did and did not manage. The projects were chosen partly for being interesting, which is a selection effect. Model versions moved during the work. Three of the four are Rust, which is a small language sample.&lt;/p&gt;

&lt;p&gt;The one number I'd most like and don't have is a like-for-like human baseline on the same corpus. That would need someone to transcribe 485 productions and reconstruct an encoder without a model, which is a real cost for a comparison nobody has funded yet.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'd tell someone starting
&lt;/h2&gt;

&lt;p&gt;Handing legacy code to a model works, and it works well enough that the interesting question is where to spend your own attention. Four projects say:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Not on the code.&lt;/strong&gt; The logic was right nearly every time. Spend it at the host, runtime and OS boundary, where every real defect in the desktop project lived and where no harness reached.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;On knowing which mode you're in.&lt;/strong&gt; Where the evidence determines the answer, expect success and build the cheap mechanical check — production numbering, reference integrity, a verbatim grounding gate. Where it doesn't, expect confident invention, and force it into the open: a divergence log, a gap inventory with plausible ranges, an ambiguity recorded rather than resolved inline. Every one of these projects has a file whose entire job is holding the things that were not derivable, and those files are what make the rest credible.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;On the checks the model can't edit.&lt;/strong&gt; Sign them, hash them, make weakening them require a human.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;On widening the input space rather than tightening the oracle.&lt;/strong&gt; The gaps that survive strong testing are exactly the ones your corpus never triggers.&lt;/p&gt;

&lt;p&gt;All four repositories are public, with the divergence logs, gap inventories, transcription artifacts and grading harnesses included — those are the parts worth reading, more than the reconstructions themselves.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;&lt;a href="https://github.com/singular-state/space-shuttle-sdk" rel="noopener noreferrer"&gt;space-shuttle-sdk&lt;/a&gt; · &lt;a href="https://github.com/singular-state/nautilus-sim" rel="noopener noreferrer"&gt;nautilus-sim&lt;/a&gt; · &lt;a href="https://github.com/singular-state/wikicarta" rel="noopener noreferrer"&gt;wikicarta&lt;/a&gt; · &lt;a href="https://github.com/singular-state/compressor" rel="noopener noreferrer"&gt;compressor&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>architecture</category>
      <category>legacycode</category>
      <category>testing</category>
    </item>
    <item>
      <title>The Decoder Scored 100%. The Encoder Scored 8.3%.</title>
      <dc:creator>Jean-Luc Martel</dc:creator>
      <pubDate>Tue, 22 Sep 2026 13:08:00 +0000</pubDate>
      <link>https://dev.to/jlmartel/the-decoder-scored-100-the-encoder-scored-83-2i49</link>
      <guid>https://dev.to/jlmartel/the-decoder-scored-100-the-encoder-scored-83-2i49</guid>
      <description>&lt;p&gt;This is the last of four experiments in AI-assisted reconstruction of legacy systems. The first three degraded the source of truth — a scanned spec, then a novel, then a memory of a product. This one removes it completely. &lt;/p&gt;

&lt;p&gt;The target is LHA's &lt;code&gt;-lh5-&lt;/code&gt; method — Haruyasu Yoshizaki's 1988 archiver, LZSS with an 8 KB window plus static Huffman.&lt;/p&gt;

&lt;p&gt;In the experiment, there is no spec and no source, only behaviour, plus an oracle that will answer any question you ask it about outputs. It is the only configuration where the two questions that actually matter become measurable rather than assertable:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Behavioural match is not understanding.&lt;/strong&gt; You can pass every test and hold a wrong model of the mechanism, with untriggered modes waiting in the part of the input space you never sampled.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A strong oracle masks confabulation.&lt;/strong&gt; The model fits observed outputs while inventing a plausible-but-wrong internal mechanism, and because the tests keep going green, the error is rewarded rather than exposed.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Measuring those requires reconstructing blind against an answer key you are not allowed to look at. Everything else in the design follows from that one constraint.&lt;/p&gt;

&lt;h2&gt;
  
  
  Choosing something the model hasn't memorised
&lt;/h2&gt;

&lt;p&gt;WinRAR was the instinct and is the wrong specimen. RAR and DEFLATE are heavily memorised, so you'd measure recall rather than reconstruction. RAR5 is far too large. Its decompressor is documented while its compressor has no public ground truth, which is exactly the half you need to grade. And it is live commercial software rather than abandonware.&lt;/p&gt;

&lt;p&gt;LHA satisfies four properties that a lot of candidates fail:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The original runs&lt;/strong&gt;, so the oracle is unlimited — compress or decompress anything on demand.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The algorithm is public&lt;/strong&gt;, so a real answer key exists and the confabulation can be &lt;em&gt;graded&lt;/em&gt; rather than merely suspected. A never-solved black box demonstrates that the pitfall exists but can never put a number on it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It's bounded&lt;/strong&gt; — a few hundred lines, reconstructable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The encoder heuristics are underdetermined by the output.&lt;/strong&gt; Match-finder strategy, minimum match length, tie-breaking, greedy versus lazy matching, block splitting are all encoder-side &lt;em&gt;choices&lt;/em&gt; that leave no trace in the decompressed bytes. That is the confabulation sweet spot.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The general LZSS-plus-Huffman scaffold is in every model's training data. LHA's specific choices are not, and those specifics are what gets measured.&lt;/p&gt;

&lt;h2&gt;
  
  
  The controls
&lt;/h2&gt;

&lt;p&gt;Three, and they're the reason the result is a measurement instead of an anecdote.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The seal.&lt;/strong&gt; The original source sits in the repo, git-ignored, hashed. At unseal, &lt;code&gt;sha256sum -c&lt;/code&gt; verified 107 of 107 files intact, and the manifest's own digest matched the value pinned in the sealing document. Reading it before the reconstruction was frozen is the single act that would have destroyed the experiment, so it was made mechanically detectable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The freeze.&lt;/strong&gt; The reconstruction was tagged and committed &lt;em&gt;before&lt;/em&gt; unsealing, so no artifact could be quietly edited to fit the answer once the answer was visible.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The cold-recall file.&lt;/strong&gt; Before any reconstruction began, a model wrote down everything it already believed about LHA, committed. Without it there is no way to distinguish "derived from behaviour" from "remembered from training," and the whole exercise collapses into a memory test.&lt;/p&gt;

&lt;p&gt;Three models did the work, deliberately split: Gemini 3.1 Pro reconstructed the decoder, Codex/GPT-5 the encoder and the cold-recall baseline, Claude ran the design thread.&lt;/p&gt;

&lt;h2&gt;
  
  
  The decoder: 100%, and it doesn't count for much
&lt;/h2&gt;

&lt;p&gt;Nineteen of nineteen round-trips, exact. The format was fully recovered.&lt;/p&gt;

&lt;p&gt;The sharpest single result lives here. LHA's generic macro defines &lt;code&gt;PBIT 5&lt;/code&gt;, so anyone reading the source would guess a 5-bit position-table field width. The &lt;code&gt;-lh5-&lt;/code&gt; method actually uses &lt;code&gt;pbit = 4&lt;/code&gt; with &lt;code&gt;np = 14&lt;/code&gt;. The reconstruction recovered the method-specific 4 purely from round-trip behaviour, against a constant that would have misled a source-reader.&lt;/p&gt;

&lt;p&gt;But checking that win against the cold-recall file deflates most of the rest. Nearly every format fact the decoder "recovered" was already in the model's committed prior: the 8 KB window, the threshold of 3 and max match of 256, the roughly 510-symbol alphabet, the 19-entry precode with its 0/1/2 zero-run encoding, the 16-bit block count, the position-slot decode. The 100% credits &lt;strong&gt;prior knowledge&lt;/strong&gt;, not derivation.&lt;/p&gt;

&lt;p&gt;Which is unsurprising, because the format is one-way determined. If you want to decode the bitstream, there is exactly one answer, and both memory and derivation converge on it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The encoder: 8.3%, and it counts for everything
&lt;/h2&gt;

&lt;p&gt;Byte-match against real &lt;code&gt;lha&lt;/code&gt;, on a fresh-seed corpus the reconstruction had never seen:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;input class&lt;/th&gt;
&lt;th&gt;trained on?&lt;/th&gt;
&lt;th&gt;byte-match&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;text&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;0/3 (0%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;source&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;0/3 (0%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;structured&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;0/3 (0%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;repetitive&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;1/3 (33%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;random&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;td&gt;2/2 (100%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;edges&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;td&gt;3/5 (60%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;trained total&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1/12 (8.3%)&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;held-out total&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;5/7 (71.4%)&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A perfect decoder coexisting with an 8% encoder is &lt;em&gt;match ≠ understanding&lt;/em&gt; in one line. The format was recoverable. The encoder's &lt;strong&gt;choices&lt;/strong&gt; were not.&lt;/p&gt;

&lt;h2&gt;
  
  
  The hypothesis was wrong, in a useful direction
&lt;/h2&gt;

&lt;p&gt;The plan predicted the classic overfitting shape: high scores on trained classes, dropping on held-out ones. The data inverted it. Held-out scored 71%, trained scored 8%.&lt;/p&gt;

&lt;p&gt;The split tracks &lt;strong&gt;difficulty, not seen versus unseen&lt;/strong&gt;. The trained classes are exactly the ones that exercise real &lt;code&gt;-lh5-&lt;/code&gt; compression; the held-out set is dominated by incompressible and trivial inputs that fall through to stored mode or hit trivial paths. Random data scores 100% because no compression heuristics ever run.&lt;/p&gt;

&lt;p&gt;So the honest statement isn't "an 8% to 71% generalisation gap." It's this: &lt;strong&gt;byte-identity is reached only where the encoder heuristics never fire. Wherever genuine compression happens, the reconstruction diverges.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The rates were identical on the trained-seed and fresh-seed corpora, so the divergence is systematic rather than instance overfitting.&lt;/p&gt;

&lt;h2&gt;
  
  
  The confabulation catalogue
&lt;/h2&gt;

&lt;p&gt;Every inferred encoder decision, graded against the now-visible source:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;decision&lt;/th&gt;
&lt;th&gt;inferred&lt;/th&gt;
&lt;th&gt;actual&lt;/th&gt;
&lt;th&gt;verdict&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;longest-match search&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;matches&lt;/td&gt;
&lt;td&gt;correct&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;tie-break among equal lengths&lt;/td&gt;
&lt;td&gt;nearest offset&lt;/td&gt;
&lt;td&gt;chain walked recent→old, updates only on strictly longer&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;derived correct&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;greedy vs lazy&lt;/td&gt;
&lt;td&gt;one-step lazy&lt;/td&gt;
&lt;td&gt;emits literal if next match is strictly longer&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;derived correct&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;block splitting&lt;/td&gt;
&lt;td&gt;"one block; unknown for larger"&lt;/td&gt;
&lt;td&gt;flush at 32 KB buffer threshold&lt;/td&gt;
&lt;td&gt;never triggered — correctly scoped&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;match-finder chain cap&lt;/td&gt;
&lt;td&gt;not modelled&lt;/td&gt;
&lt;td&gt;a hard limit makes the finder &lt;strong&gt;non-exhaustive&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;wrong, and it passed anyway&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Huffman code-length assignment&lt;/td&gt;
&lt;td&gt;canonical, tie order unmatched&lt;/td&gt;
&lt;td&gt;lengths assigned in &lt;strong&gt;heap-extraction order&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;visible divergence&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Two of those are clean wins. Nearest-offset tie-breaking and one-step lazy matching are both marked as unknown in the cold-recall file — "do not know whether &lt;code&gt;lha -lh5-&lt;/code&gt; does this," "not a specific memory." Derived from black-box behaviour, with documented prior ignorance.&lt;/p&gt;

&lt;p&gt;There's a caveat that inverts on inspection. Codex wrote both the recall file and the encoder, which normally weakens an independence claim. Here it strengthens it: a model cannot conceal prior knowledge from its own committed statement of ignorance. Deriving both heuristics after recording that it didn't know them is the cleanest evidence in the run.&lt;/p&gt;

&lt;p&gt;The failure is concentrated in one place. LHA builds a frequency heap and assigns code lengths in the order symbols leave the heap, governed by the exact comparison semantics of its sift-down — not by symbol value. Textbook canonical Huffman breaks ties by symbol index, which produces different lengths for equal-frequency symbols, which cascades through the entire bitstream. The reconstruction localised the problem correctly and even tried a heap hypothesis, but never replicated the precise sift order.&lt;/p&gt;

&lt;h2&gt;
  
  
  The second hypothesis was also wrong, and that's the finding
&lt;/h2&gt;

&lt;p&gt;The project was built to show that a strong oracle masks confabulation. It mostly didn't.&lt;/p&gt;

&lt;p&gt;The core error — the Huffman ordering — is a &lt;strong&gt;visible&lt;/strong&gt; divergence. It fails the byte test loudly. The oracle caught it, exactly as an oracle should. Only two gaps were genuinely hidden: the never-triggered block split, and the unmodelled chain cap, which is latent because the corpus never produced input self-similar enough to expose it.&lt;/p&gt;

&lt;p&gt;Both are artifacts of a corpus that tops out at 8 KiB.&lt;/p&gt;

&lt;p&gt;So the masking risk isn't a property of the oracle's strength. &lt;strong&gt;It's a property of the input space you sampled.&lt;/strong&gt; A strong oracle over a narrow corpus hides exactly the mechanisms your corpus never triggers, and it hides them silently, because everything it &lt;em&gt;can&lt;/em&gt; see is green. Making the oracle stronger doesn't help. Making the corpus wider does.&lt;/p&gt;

&lt;p&gt;That reframing is more useful than the result I expected to get, and I would not have got it by reasoning about it. It needed the sealed envelope.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it cost to know any of this
&lt;/h2&gt;

&lt;p&gt;Final tally across the encoder decisions: six recalled-correct, five derived-correct, one derived-wrong-but-passed, two never-triggered, one visible divergence.&lt;/p&gt;

&lt;p&gt;The infrastructure to produce those thirteen data points — the pinned oracle, the deterministic corpus generator, the seal and its manifest, the cold-recall protocol, the freeze tag, the grading harness — is most of the repository. The reconstruction itself is the small part.&lt;/p&gt;

&lt;p&gt;That ratio is the practical lesson. If you want to know whether an AI-assisted reconstruction actually understood the system, rather than whether it passed, you have to build the apparatus that can tell you, and you have to build it before you start. Afterwards, every artifact is contaminated by the answer.&lt;/p&gt;

&lt;p&gt;One thing remains open. A fully independent contamination estimate needs a repeat where the recall file and the encoder come from different model families, closing the theoretical shared-prior channel that the current caveat only argues around.&lt;/p&gt;

&lt;p&gt;Next, the wrap-up: what four projects across four degrees of source degradation say about where the current generation of models actually fails, and why the failures kept landing in the same place.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Code: &lt;a href="https://github.com/singular-state/compressor" rel="noopener noreferrer"&gt;https://github.com/singular-state/compressor&lt;/a&gt;. LHA was written by Haruyasu Yoshizaki in 1988; the original source is used here only as a private grading key, held out during reconstruction and consulted once. The reconstruction is clean-room, so the measured gap between "passes the oracle" and "matches the source" is legitimate.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>computerscience</category>
      <category>machinelearning</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>Rebuilding Encarta showed me exactly where AI-written code breaks</title>
      <dc:creator>Jean-Luc Martel</dc:creator>
      <pubDate>Fri, 18 Sep 2026 14:01:00 +0000</pubDate>
      <link>https://dev.to/jlmartel/rebuilding-encarta-showed-me-exactly-where-ai-written-code-breaks-3oj0</link>
      <guid>https://dev.to/jlmartel/rebuilding-encarta-showed-me-exactly-where-ai-written-code-breaks-3oj0</guid>
      <description>&lt;p&gt;The bug that froze the window was type-correct. It compiled, &lt;code&gt;cargo check&lt;/code&gt; passed, the tests passed, and the operating system reported the application as not responding.&lt;/p&gt;

&lt;p&gt;It was a &lt;code&gt;Save As&lt;/code&gt; dialog called through the Tauri plugin's blocking API from inside a command, which blocks the event loop the WebKit window is running on. Nothing in the type system objects to that. Nothing in a headless harness notices. The only way to find it is to be a person, at a real desktop, clicking the button.&lt;/p&gt;

&lt;p&gt;That defect is the whole finding of this project, and the project took four phases to earn the right to state it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The setup
&lt;/h2&gt;

&lt;p&gt;Wikicarta rebuilds Microsoft Encarta on Wikipedia — the visual browser, the atlas, the timeline, the research organiser, MindMaze — as a Tauri v2 desktop app in Rust and React, with an instant toggle between Live mode against the Wikimedia API and Offline mode against a local ZIM archive.&lt;/p&gt;

&lt;p&gt;It is the third of four experiments in what current AI can do with legacy systems, and it occupies the worst position of the four. HAL/S had a formal spec and an independent interpreter to check against. Nautilus had a novel and built its own physics oracle. Wikicarta has neither. The source of truth is &lt;em&gt;what the product felt like&lt;/em&gt;, and the only oracle is human judgement. There is no test that tells you whether the category wheel feels like Encarta.&lt;/p&gt;

&lt;p&gt;An AI agent wrote essentially all of it. What follows is where that went well, where it went badly, and the fact that those two places were not the ones I expected.&lt;/p&gt;

&lt;h2&gt;
  
  
  The modern substrate is never the shape its docs claim
&lt;/h2&gt;

&lt;p&gt;The offline story was supposed to be a pure-Rust ZIM reader. The &lt;code&gt;zim&lt;/code&gt; crate looked right: random access, deferred loading, &lt;code&gt;Send&lt;/code&gt; and &lt;code&gt;Sync&lt;/code&gt;. It panicked with an integer overflow in &lt;code&gt;parse_article_list&lt;/code&gt; before finishing the open call, against a real modern archive.&lt;/p&gt;

&lt;p&gt;That pattern recurred with no relationship between the cases. TextExtracts HTML turned out unusable as a reader format, so article HTML comes from &lt;code&gt;action=parse&lt;/code&gt; instead. Live image URLs came back protocol-relative — &lt;code&gt;//upload...&lt;/code&gt;, not the &lt;code&gt;https://...&lt;/code&gt; everything downstream assumed.&lt;/p&gt;

&lt;p&gt;Three unrelated features, one rule: &lt;strong&gt;for a revival, the modern content, format or API is always slightly different from its specification and from the model's memory of it.&lt;/strong&gt; Probe a real sample before building on it. The AI will confidently build against the documented shape, because the documented shape is what it was trained on.&lt;/p&gt;

&lt;h2&gt;
  
  
  The decision that paid for everything
&lt;/h2&gt;

&lt;p&gt;Before it was provably needed, the reader was decoupled from its content source behind a single trait:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;trait&lt;/span&gt; &lt;span class="n"&gt;ArticleSource&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;get_article&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Article&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;SearchResult&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;get_image&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Adding a whole second content source later — live Wikipedia alongside offline ZIM — was two commands and a mode flag. No reader rewrite. Swapping the storage layer from JSON files to SQLite was invisible above the command boundary.&lt;/p&gt;

&lt;p&gt;For software that assumed one sealed data source — a CD, a bundled database, a mainframe — inserting that seam first is what converts every later modernisation from a rewrite into an adapter. It is also the single decision an AI agent is least likely to make unprompted, because at the moment you make it there is exactly one source and the abstraction looks like overhead.&lt;/p&gt;

&lt;p&gt;Two features in the final phase were pre-paid by decisions like it. The attribution aggregator became a &lt;code&gt;GROUP BY&lt;/code&gt; rather than a re-fetch, because provenance had been stamped at save time back when the notes feature was built. Bundling the &lt;code&gt;kiwix-serve&lt;/code&gt; binary into the package was a two-line change, because binary discovery had long been a prioritised candidate list rather than a hard-coded path.&lt;/p&gt;

&lt;p&gt;Packaging work disproportionately cashes in — or punishes — architectural decisions made when the feature that needed them didn't exist yet.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testability turned into architecture, which turned out to be good
&lt;/h2&gt;

&lt;p&gt;The only layer testable without a desktop window is pure functions. So the code got steadily shaped so that the hard parts &lt;em&gt;are&lt;/em&gt; pure functions: URL rewriting, upstream reconstruction, cache naming, database round-tripping and ordering, bookmark deduplication, legacy JSON import. The Rust suite went from nothing to 23 offline tests, and each feature's desktop-only remainder shrank to a short explicit list.&lt;/p&gt;

&lt;p&gt;"What can I verify headlessly?" is a useful question about &lt;em&gt;how to structure code&lt;/em&gt;, not just about how to test it. Under an AI agent it becomes close to essential, because the agent's verification loop is only as good as the surface it can reach.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the defects actually were
&lt;/h2&gt;

&lt;p&gt;The pure logic — parsing, backoff, the media-cache URL rewrite, database ordering, live-title normalisation — compiled correct and passed on the first or second attempt. Consistently.&lt;/p&gt;

&lt;p&gt;Every real bug was at the runtime seam:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The blocking &lt;code&gt;Save As&lt;/code&gt; that froze the WebKit window.&lt;/li&gt;
&lt;li&gt;DOM nodes inside an &lt;code&gt;&amp;lt;iframe&amp;gt;&lt;/code&gt; coming from a &lt;strong&gt;different JavaScript realm&lt;/strong&gt;, so an &lt;code&gt;instanceof Element&lt;/code&gt; check in the parent React shell fails on a clicked target that is unambiguously an element. Realm-safe DOM handling is mandatory when the app owns iframe content but drives it from the parent.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both are invisible to the type system and to any headless harness. Both required a person at the real window.&lt;/p&gt;

&lt;p&gt;The implication for anyone running an agent on desktop software: &lt;strong&gt;the logic is rarely where the risk is.&lt;/strong&gt; Human validation time should be spent almost entirely at the host, runtime and OS boundary, and hardly at all reviewing the algorithm the model just wrote.&lt;/p&gt;

&lt;p&gt;There is a compounding effect worth noting. Once the blocking-dialog lesson was recorded, the archive picker was built on the non-blocking callback pattern from the start — the backend opens the dialog with a callback, validates and persists inside it, and reports back over an event the React shell listens for. A hard-won runtime lesson, written down, becomes a convention rather than a bug re-lived.&lt;/p&gt;

&lt;h2&gt;
  
  
  Checking a model with code beats checking it with a model
&lt;/h2&gt;

&lt;p&gt;MindMaze needs quiz questions, so a standalone crate generates them from article text through an LLM. Model output is treated as untrusted input: strict JSON parse, structural validation, then a verbatim &lt;strong&gt;grounding gate&lt;/strong&gt; — the answer must appear literally in the source article — before anything is stored. Questions carry the revision id they were generated from, so they can be flagged stale when the article moves.&lt;/p&gt;

&lt;p&gt;The roadmap had proposed a second LLM as a fact-checker. A deterministic string check does the job for a fraction of the cost, and the rule generalises: &lt;strong&gt;reach for a model to check a model only when the property genuinely isn't codeable.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The first real run against &lt;em&gt;Mount Everest&lt;/em&gt; then demonstrated the limit of that rule. Two of the three questions were excellent, including one on the 1953 first ascent with genuinely plausible distractors. The third asked which of the options is a section heading. The answer was "Name."&lt;/p&gt;

&lt;p&gt;That question is perfectly grounded. "Name" is a section heading and it appears verbatim in the source, so the gate accepted it. It also tests document structure rather than knowledge. &lt;em&gt;Is the answer in the source?&lt;/em&gt; and &lt;em&gt;is this a good question?&lt;/em&gt; are different properties, and only the first one is codeable. The fix belonged at the prompt layer — instruct the model to ask about substantive facts, never structure or formatting — which eliminated the meta-questions on the next run.&lt;/p&gt;

&lt;p&gt;Quality control for LLM output is layered: a cheap deterministic gate for the codeable invariant, prompt engineering for the one that isn't. Confusing the two gets you a system that passes its own checks and produces garbage.&lt;/p&gt;

&lt;h2&gt;
  
  
  Modernisation re-opens every surface the original had sealed
&lt;/h2&gt;

&lt;p&gt;A CD-era encyclopedia needed no TLS trust roots, no rate-limit backoff, no per-source provenance, no SSRF guard, no cross-platform custom-scheme origins, no data migration path. Each modern dependency reintroduces one.&lt;/p&gt;

&lt;p&gt;The media cache restricts upstream hosts to &lt;code&gt;*.wikimedia.org&lt;/code&gt; so it isn't an open proxy. User-selected ZIM files are validated for existence, extension and non-emptiness. The timeline parses presentation HTML defensively. None of this is polish. It is the actual cost of "keep the experience, replace the substrate," and it should be budgeted as first-class work rather than discovered late.&lt;/p&gt;

&lt;h2&gt;
  
  
  The last mile is where the sandbox stops being able to prove anything
&lt;/h2&gt;

&lt;p&gt;Every earlier phase ended with a headlessly provable artifact. Packaging produced the first deliverable the agent's environment structurally could not generate — there is no &lt;code&gt;cargo-tauri&lt;/code&gt; and no &lt;code&gt;dpkg-deb&lt;/code&gt; in it, so the &lt;code&gt;.deb&lt;/code&gt; and the AppImage can only be built by a human on a real host.&lt;/p&gt;

&lt;p&gt;What kept that honest was decomposing the deliverable into layers each verifiable in isolation: config validity, the fetch script (run end to end against the real 20 MB tarball), runtime path resolution with its own tests. Only the final bundler invocation stayed unproven — and rather than paper over that with a CI workflow nobody had run, the repo says so.&lt;/p&gt;

&lt;p&gt;That work also surfaced a boundary the configuration layer silently drops. Tauri copies bundled resources into the payload but does not guarantee the executable bit survives, which varies by target and archive format. A bundled binary can land non-executable and fail at spawn with a permission error that points nowhere useful. The fix lives in runtime code, not packaging config — the resolver &lt;code&gt;chmod&lt;/code&gt;s the binary before returning it.&lt;/p&gt;

&lt;p&gt;A related lesson came from the memory pass. The roadmap prescribed virtual scrolling for an assumed giant rendered DOM. It was architecturally inapplicable: articles render inside &lt;code&gt;&amp;lt;iframe srcDoc&amp;gt;&lt;/code&gt;, a separate browsing context whose internal DOM React cannot window, and only one is ever live. The actual unbounded growth was one layer up — a reader history that pinned every visited article's full HTML in the heap forever. &lt;strong&gt;When the roadmap and the architecture disagree, re-read the architecture.&lt;/strong&gt; An inherited roadmap encodes assumptions that later decisions have already invalidated.&lt;/p&gt;

&lt;p&gt;And since WebKitGTK has no &lt;code&gt;performance.memory&lt;/code&gt;, the app now measures and displays its own retained HTML instead. The instrument ships with the product and works on the real target, rather than existing only in a Chromium devtools session that the shipping app never runs in.&lt;/p&gt;

&lt;h2&gt;
  
  
  The constraint was never throughput
&lt;/h2&gt;

&lt;p&gt;Across every substantial feature, the agent's implement-and-verify cycle was fast and mostly correct. Each feature still ended with a short list of things only a person at the real window could confirm, and those checks are serialised.&lt;/p&gt;

&lt;p&gt;That is the bottleneck in AI-assisted desktop revival. Not writing the code. The human-in-the-loop runtime check that no headless harness currently replaces — which is also, precisely, where all the bugs were.&lt;/p&gt;

&lt;p&gt;Next: the same question with the tests made as strong as possible and the answer key sealed in an envelope, to find out whether passing every test means the model understood anything.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Code: &lt;a href="https://github.com/singular-state/wikicarta" rel="noopener noreferrer"&gt;https://github.com/singular-state/wikicarta&lt;/a&gt;. Not affiliated with Microsoft; Wikipedia content is CC-BY-SA and the app ships an attribution exporter for the sources you actually used.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>rust</category>
      <category>tauri</category>
      <category>webdev</category>
    </item>
    <item>
      <title>AI proved that the Nautilus crushes at 340 metres. Verne dives it to 16,000.</title>
      <dc:creator>Jean-Luc Martel</dc:creator>
      <pubDate>Thu, 17 Sep 2026 16:09:00 +0000</pubDate>
      <link>https://dev.to/jlmartel/ai-proved-that-the-nautilus-crushes-at-340-metres-verne-dives-it-to-16000-28nf</link>
      <guid>https://dev.to/jlmartel/ai-proved-that-the-nautilus-crushes-at-340-metres-verne-dives-it-to-16000-28nf</guid>
      <description>&lt;p&gt;Twenty Thousand Leagues Under the Sea gives the Nautilus a hull of 5 cm plating on a 4 m radius. Thin-cylinder hoop stress puts the crush depth at 342 metres. Verne narrates a dive to 16,000.&lt;/p&gt;

&lt;p&gt;At 16,000 m the external pressure is about 1,608 atmospheres and the hoop stress is 12.9 GPa, roughly 47 times the plating's yield. Surviving it would need approximately 2.34 metres of steel, which weighs more than the entire boat.&lt;/p&gt;

&lt;p&gt;That number came out of a simulator, not a spreadsheet, and the simulator is the point. This is the second of four projects testing what current AI can do with legacy systems, and the variable being changed is the quality of the source. The last one had a formal spec, real preserved code, and an independent implementation to check against. This one has a novel.&lt;/p&gt;

&lt;h2&gt;
  
  
  Extracting a spec from fiction
&lt;/h2&gt;

&lt;p&gt;The project's thesis is one sentence: &lt;strong&gt;legacy documentation lies by omission, not by error.&lt;/strong&gt; Verne itemises the art in the Nautilus's salon. He never gives the air budget.&lt;/p&gt;

&lt;p&gt;So the first phase produced no code at all. Two independent claim-extraction passes ran chapter-by-chapter over the French original, each tagging every physical assertion with its quote, chapter, category, and a precision marker — stated, hedged, implied, or demonstrated. The two passes were then diffed and reconciled into &lt;strong&gt;731 claims&lt;/strong&gt;, with a human reviewing the reconciliation. Contradictions were recorded and deliberately &lt;em&gt;not&lt;/em&gt; resolved, because which resolution you pick changes the answer and that choice needs to be visible rather than buried.&lt;/p&gt;

&lt;p&gt;Then the harder half. A simulator needs numbers the novel never supplies, and inventing them quietly is how you get a result that means nothing. Every such parameter became a &lt;strong&gt;gap entry&lt;/strong&gt; with a plausible range and a sourced rationale, and the gate rule was absolute: every parameter in the spec traces to either a claim with a chapter citation or a gap with a range. Nothing enters as a bare constant.&lt;/p&gt;

&lt;p&gt;Ranges are anchored where possible to &lt;em&gt;Plongeur&lt;/em&gt;, the French Navy submarine launched in April 1863 — the actual state of the art Verne could have known about. Plongeur was 43 m and about 420 tonnes, with 23 compressed-air tanks at 12.5 bar occupying 153 m³ of its hull to drive an 80 hp engine to 4 knots and a range of 5 nautical miles.&lt;/p&gt;

&lt;p&gt;Two things follow from that immediately. Stored gas and ballast machinery eat an enormous fraction of a submarine's internal volume, so the Nautilus's &lt;em&gt;breathable&lt;/em&gt; space is far smaller than its 1,500 m³ envelope. And 60 kW moved a 420-tonne boat at 4 knots, which sets expectations for what Verne's stated 1.47 MW should do to 1,500 tonnes.&lt;/p&gt;

&lt;h2&gt;
  
  
  The core is a pure function
&lt;/h2&gt;

&lt;p&gt;The simulator is Ada, built as a pure function of &lt;code&gt;(spec, seed, command stream)&lt;/code&gt;. No wall clock, no filesystem access, no network, no environment reads inside the core. Everything crosses a single seam — JSON Lines on stdin and stdout — and the UI, the genetic algorithm, the fuzzer, the test harness and the save files all speak the same protocol. There are no side channels.&lt;/p&gt;

&lt;p&gt;Three consequences fall out of that shape, and all three matter for supervising an AI:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Any result reproduces from files in the repo plus a binary hash.&lt;/strong&gt; The spec is canonicalised and SHA-256'd by the core itself; the wrapper cross-checks and aborts on mismatch. Every recording is pinned to a spec hash.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The protocol was frozen before the physics existed.&lt;/strong&gt; Determinism, replay and malformed-input fuzzing were green in the one check harness before a single equation landed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The invariants are append-only and human-signed.&lt;/strong&gt; Twelve of them live in &lt;a href="https://github.com/singular-state/nautilus-sim/tree/main/invariants" rel="noopener noreferrer"&gt;&lt;code&gt;invariants/&lt;/code&gt;&lt;/a&gt;, covering physical bounds, monotonicity, and event ordering — depth is never negative, stored energy never rises, CO₂ only increases while sealed and may drop only to fresh air via a surface renewal, no state tick may follow a crush event.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That last one is the load-bearing supervision decision. When the fuzzer finds a violation, the repair workflow says the AI patches &lt;strong&gt;the core, never the invariant&lt;/strong&gt;. Weakening an invariant to make an exploit pass is prevented by a checksum in &lt;code&gt;invariants/manifest.sha256&lt;/code&gt; that only a human re-signs. The model is free to fix the physics and structurally unable to move the goalposts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Five findings
&lt;/h2&gt;

&lt;p&gt;Running the committed spec under real physics and comparing to the narrative:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;axis&lt;/th&gt;
&lt;th&gt;the legend&lt;/th&gt;
&lt;th&gt;the physics&lt;/th&gt;
&lt;th&gt;robust to gaps?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;F1&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;buoyancy&lt;/td&gt;
&lt;td&gt;dives at will&lt;/td&gt;
&lt;td&gt;under-ballasted — the mass budget only closes in &lt;em&gt;fresh&lt;/em&gt; water&lt;/td&gt;
&lt;td&gt;yes, it's arithmetic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;F2&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;speed&lt;/td&gt;
&lt;td&gt;50 knots&lt;/td&gt;
&lt;td&gt;~15 kn; 50 kn needs &lt;strong&gt;~24×&lt;/strong&gt; the stated power&lt;/td&gt;
&lt;td&gt;yes, 15–22 kn across the drag range&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;F3&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;range&lt;/td&gt;
&lt;td&gt;20,000 leagues&lt;/td&gt;
&lt;td&gt;~1,400 nmi per charge → 30–4,000 recharges of a battery whose capacity is never stated&lt;/td&gt;
&lt;td&gt;capacity unknown to 100×&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;F4&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;depth&lt;/td&gt;
&lt;td&gt;16,000 m&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;crushes at ~340 m&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;yes, 249–435 m&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;F5&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;endurance&lt;/td&gt;
&lt;td&gt;weeks submerged&lt;/td&gt;
&lt;td&gt;6–211 h; no CO₂ scrubbing means a &lt;strong&gt;1–2 day surface tether&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;endurance unknown to 35×&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;F1 is the most elegant. Verne's mass budget is internally consistent — in fresh water, where one cubic metre conveniently weighs a tonne. In seawater at 1,025 kg/m³ the same 1,500 m³ hull displaces 1,537,705 kg, and the boat with main ballast full reaches only 1,507,200 kg. It is about 30 tonnes positively buoyant and cannot submerge on main ballast alone. The arithmetic is fine. The ocean is the wrong one.&lt;/p&gt;

&lt;p&gt;F5 is the subtlest, and it cuts both ways. Verne explicitly states the Nautilus has no CO₂ scrubbing — absorbing it would need caustic-potash canisters he says aren't carried — so air is refreshed only by surfacing. Where he lets that constraint bite, he is &lt;em&gt;right&lt;/em&gt;: the roughly 48-hour crisis under the Antarctic ice sits squarely inside the plausible band. The failure is everywhere else, where the narrative implies indefinite submersion that the stated design forbids.&lt;/p&gt;

&lt;p&gt;And the single most operationally important number in the book — how long the boat can stay under — ranges across 6 to 211 hours depending on parameters Verne never gives. That 35× spread &lt;em&gt;is&lt;/em&gt; the finding.&lt;/p&gt;

&lt;h2&gt;
  
  
  The genetic algorithm cheats, correctly
&lt;/h2&gt;

&lt;p&gt;With the physics quiescent, the question becomes: can a physically honest Nautilus be &lt;em&gt;designed&lt;/em&gt; to reach Verne's? A GA got 29 design genes and a push-to-limit mission that dives until hull stress hits its safe limit and cruises until the battery is flat.&lt;/p&gt;

&lt;p&gt;The best evolved champion reaches &lt;strong&gt;562 metres&lt;/strong&gt;. Verne claims 16,000. The gap is about &lt;strong&gt;28×&lt;/strong&gt;, after pushing every parameter to its most favourable plausible value — the strongest steel, the thickest plating, the biggest battery, the sleekest hull.&lt;/p&gt;

&lt;p&gt;The interesting part is what the optimiser did first. Its opening move to extend endurance was to add &lt;strong&gt;CO₂ scrubbing at 6.5 L/s&lt;/strong&gt; — the exact system Verne states the Nautilus lacks, and the omission behind F5's surface tether. With no knowledge of the novel and no term in its objective mentioning air, the GA independently identified and fixed the book's single most consequential design gap. Range roughly doubled once the CO₂ clock came off.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the fuzzer found
&lt;/h2&gt;

&lt;p&gt;Nothing, which took some doing to trust.&lt;/p&gt;

&lt;p&gt;A 24-hour random-command soak ran 42 lives and 879,643 ticks, killing the boat 29 times by crushing it, and produced &lt;strong&gt;zero invariant violations&lt;/strong&gt;. Five consecutive fuzz campaigns, sixty more lives, also zero. A harness that finds nothing is indistinguishable from a harness that is broken, so it was validated against a deliberately poisoned invariant — which it caught, delta-debugged from seven commands down to two, and packaged as a reproducible exploit.&lt;/p&gt;

&lt;p&gt;The only finding in the whole loop is filed under &lt;a href="https://github.com/singular-state/nautilus-sim/tree/main/exploits" rel="noopener noreferrer"&gt;&lt;code&gt;exploits/001-objective-pinning&lt;/code&gt;&lt;/a&gt;, and it is a flaw in the &lt;em&gt;experiment&lt;/em&gt;, not the physics: the GA had been optimising survival rather than performance, because the original controller pinned depth and distance to fixed targets. No core patch. A design-of-experiment fix, and the Pareto front went from a collapsed cluster to a real trade-off surface.&lt;/p&gt;

&lt;p&gt;Then the frozen Ada core was re-implemented in TypeScript and both were replayed against a golden corpus, with any divergence defined in advance as a TypeScript bug. Event sequences matched exactly. The worst numeric delta was about 5×10⁻⁷ — and all of it traces to the Ada core rounding its output to six decimals at the wire. The two integrators actually agree to about 10⁻⁷, tighter than the reference bothers to report. The only genuine computational difference is the actuator-disk cube root, where Ada's &lt;code&gt;X ** (1.0/3.0)&lt;/code&gt; and JavaScript's &lt;code&gt;Math.pow&lt;/code&gt; disagree in the last bits and surface as 10⁻¹⁰ watts.&lt;/p&gt;

&lt;h2&gt;
  
  
  No oracle means you build one
&lt;/h2&gt;

&lt;p&gt;HAL/S could check itself against an independent interpreter written by someone else. There is no independent implementation of Jules Verne. The oracle here had to be constructed, which means the credibility of every number above rests entirely on the scaffolding — the two-pass claim extraction, the traceability gate, the frozen protocol, the human-signed invariants, the determinism enforced before any physics existed, the harness validated against a poisoned check.&lt;/p&gt;

&lt;p&gt;An AI will produce a confident simulation of a submarine with far less than that. It will also produce confident numbers that mean nothing, and from the outside the two look identical.&lt;/p&gt;

&lt;p&gt;Next: no spec and no oracle again, but this time the thing being rebuilt is a product people remember using, the substrate underneath it has been replaced, and every defect that mattered turned out to be invisible to the tests.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Code: &lt;a href="https://github.com/singular-state/nautilus-sim" rel="noopener noreferrer"&gt;https://github.com/singular-state/nautilus-sim&lt;/a&gt;. Every figure regenerates from the committed repo via &lt;code&gt;scripts/check.sh&lt;/code&gt;; each finding re-derives from the hash-pinned canonical spec, and each GA champion replays from its &lt;code&gt;(genome, spec_hash, seed, scenario)&lt;/code&gt; triple. Pinned GNAT, fixed timestep, seeded PCG — byte-identical replay.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>simulation</category>
      <category>ada</category>
      <category>science</category>
    </item>
    <item>
      <title>NASA's Shuttle language survives only as a 1980 scan. I had AI rebuild it.</title>
      <dc:creator>Jean-Luc Martel</dc:creator>
      <pubDate>Wed, 09 Sep 2026 18:15:48 +0000</pubDate>
      <link>https://dev.to/jlmartel/nasas-shuttle-language-survives-only-as-a-1980-scan-i-had-ai-rebuild-it-1mee</link>
      <guid>https://dev.to/jlmartel/nasas-shuttle-language-survives-only-as-a-1980-scan-i-had-ai-rebuild-it-1mee</guid>
      <description>&lt;p&gt;The complete specification of the language NASA wrote the Space Shuttle's flight software in is a 20-megabyte bag of page images. No text layer. Some pages sit at an angle.&lt;/p&gt;

&lt;p&gt;That document is IR-542, and nothing supersedes it. If you want to know whether a bit-string partition is legal on the left of an assignment, the answer is a photograph of a page printed in 1980.&lt;/p&gt;

&lt;p&gt;I wanted HAL/S to run again — lexer, parser, type checker, interpreter — and I wanted AI to write essentially all of it, because the interesting question isn't whether a dead language can be revived. It's what the current generation of models can do when the source of truth has been degraded, and what a human still has to hold.&lt;/p&gt;

&lt;p&gt;This is the first of four projects that vary exactly that. HAL/S is the easy end: a formal spec exists, real preserved code exists, and an independent implementation exists to check the answers against. Best-case conditions. Worth knowing what best case buys you.&lt;/p&gt;

&lt;h2&gt;
  
  
  The obvious OCR strategy is wrong
&lt;/h2&gt;

&lt;p&gt;Run three OCR engines, take the majority vote, move on. This works for prose and fails for grammars, for a reason that took a diagnosis pass to make explicit rather than assume.&lt;/p&gt;

&lt;p&gt;OCR errors are &lt;strong&gt;correlated across engines&lt;/strong&gt;. Tesseract, Textract and the PDF's embedded Envision layer are all reading the same glyphs at the same resolution with broadly similar priors, so they tend to misread &lt;code&gt;::=&lt;/code&gt; the same way and &lt;code&gt;|&lt;/code&gt; the same way. A vote between them doesn't cancel error, it launders it — three engines agreeing confidently on &lt;code&gt;:::&lt;/code&gt; when the page says &lt;code&gt;::=&lt;/code&gt;. And the deeper problem: &lt;strong&gt;no aggregation method can recover a candidate that no engine produced.&lt;/strong&gt; If all three miss a character, fusion has nothing to fuse.&lt;/p&gt;

&lt;p&gt;For prose that's survivable, because context repairs it. For BNF it's fatal — the metacharacters &lt;em&gt;are&lt;/em&gt; the content, and there is no redundancy to recover them from.&lt;/p&gt;

&lt;p&gt;So the pipeline sorted pages into tiers by how much OCR could be trusted:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tier&lt;/th&gt;
&lt;th&gt;Content&lt;/th&gt;
&lt;th&gt;Trust&lt;/th&gt;
&lt;th&gt;Disposition&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;A&lt;/td&gt;
&lt;td&gt;Prose&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;OCR, spot-check&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;B&lt;/td&gt;
&lt;td&gt;Tables&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;td&gt;OCR + structural verify&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;C&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;BNF productions&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Low&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Hand-transcribe, verify against the scan&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;D&lt;/td&gt;
&lt;td&gt;2D source notation&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Low&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Vision model, then verify&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Appendix G — the working grammar, 485 productions across physical pages 295–306 — is Tier C in its entirety. It got one strong engine as the authoritative draft (Textract), with Tesseract and Envision used &lt;em&gt;only&lt;/em&gt; to flag disagreement for re-inspection. Never as voters. Then every one of the 485 productions was read by eye against a zoomed crop of the page image.&lt;/p&gt;

&lt;p&gt;That by-eye pass is the human contribution to this project, and it is not incidental. The AI ran the renders, the despeckling, the extraction, the reconciliation and the assembly. It could not manufacture a character that the scan had eaten.&lt;/p&gt;

&lt;p&gt;What it &lt;em&gt;could&lt;/em&gt; do is design checks that make the verification mechanical rather than faith-based. Two of them carried real weight:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Numbering integrity.&lt;/strong&gt; The 485 production numbers came out as exactly &lt;code&gt;1..485&lt;/code&gt;, no gaps, no duplicates. The numbers are the spec's own and the last one is 485, so this proves nothing was dropped or double-counted across twelve pages.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reference integrity.&lt;/strong&gt; Every &lt;code&gt;&amp;lt;nonterminal&amp;gt;&lt;/code&gt; on a right-hand side either has a defining production or is one of 22 known lexical primitives. No dangling references, no misspellings.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Neither check needs a human, and between them they catch the entire class of "a page got skipped" and "a name got mangled" errors. The eyeballs were then spent only on what the checks can't see.&lt;/p&gt;

&lt;p&gt;A small, characteristic detail: a human skim of the PDF reported that some pages "have an angle," which drove an early plan to deskew before OCR. Measuring it found skew under 0.3°, so the deskew step was dropped. The estimate was replaced by a number, and the number deleted a stage of the pipeline.&lt;/p&gt;

&lt;p&gt;Residual ambiguities went into &lt;a href="https://github.com/singular-state/space-shuttle-sdk/blob/main/DIVERGENCES.md" rel="noopener noreferrer"&gt;&lt;code&gt;DIVERGENCES.md&lt;/code&gt;&lt;/a&gt; rather than getting guessed inline. One was a scaling glyph the scan left uncertain, later resolved to &lt;code&gt;@&lt;/code&gt; against the spec's own prose describing it. Another, production 348, is logged as an inference from physical scan damage and marked as such. Guessing silently would have been faster and would have made every downstream claim worthless.&lt;/p&gt;

&lt;h2&gt;
  
  
  Then the easy part
&lt;/h2&gt;

&lt;p&gt;With a verified grammar, building the thing is ordinary compiler work, and the AI was very good at it. The result is in plain Rust with &lt;strong&gt;no cargo and no third-party crates&lt;/strong&gt; — the crates link in dependency order through a two-stage &lt;code&gt;rustc&lt;/code&gt; build in &lt;a href="https://github.com/singular-state/space-shuttle-sdk/blob/main/build.sh" rel="noopener noreferrer"&gt;&lt;code&gt;build.sh&lt;/code&gt;&lt;/a&gt;. There is nothing to install.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;./build.sh cli
&lt;span class="nv"&gt;$ &lt;/span&gt;./build/hals crates/hals-syntax/tests/corpus/realworld/HELLO.hal
        THE BEGINNING
          1     HELLO, WORLD!
                    2     RON BURKEY SAYS ISN&lt;span class="s1"&gt;'T THIS FUN?
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The north star was real preserved source, not samples anyone wrote for the occasion: twelve byte-for-byte Shuttle-era programs from the &lt;a href="https://www.ibiblio.org/apollo/" rel="noopener noreferrer"&gt;Virtual AGC&lt;/a&gt; project. All twelve now run. &lt;code&gt;MATVECS3&lt;/code&gt; puts 22 vector and matrix operations through 400 iterations and prints &lt;code&gt;TEST SUCCESSFUL&lt;/code&gt;. &lt;code&gt;DATATYPES&lt;/code&gt; reproduces every value its own comments say it should. &lt;code&gt;TEST7&lt;/code&gt; links against a separately compiled COMPOOL and exercises true NAME pointers.&lt;/p&gt;

&lt;p&gt;Arithmetic is where fidelity stops being a slogan. SINGLE precision on the Shuttle's general-purpose computer is IBM System/360 short hexadecimal floating point: it truncates toward zero rather than rounding to nearest, and its precision wobbles between 21 and 24 bits depending on the value. IEEE &lt;code&gt;f32&lt;/code&gt; would have been easier and would have produced different numbers. Authentic is the default; &lt;code&gt;--modern&lt;/code&gt; gives you &lt;code&gt;f64&lt;/code&gt; when you want to use HAL/S as a live language rather than as a museum exhibit. You can flip between them in the browser playground and watch the digits move.&lt;/p&gt;

&lt;h2&gt;
  
  
  Checking against something that isn't yourself
&lt;/h2&gt;

&lt;p&gt;Passing your own tests means your implementation agrees with your understanding, which is the thing under suspicion. So every program is also run through Ron Burkey's &lt;code&gt;yaHAL-S&lt;/code&gt;, an independent HAL/S interpreter, and compared value-for-value by &lt;a href="https://github.com/singular-state/space-shuttle-sdk/blob/main/tools/oracle_diff.py" rel="noopener noreferrer"&gt;&lt;code&gt;tools/oracle_diff.py&lt;/code&gt;&lt;/a&gt;. Every program the oracle can run, we match exactly — including all 339 numbers &lt;code&gt;DATATYPES&lt;/code&gt; emits. The four it can't run, ours handles.&lt;/p&gt;

&lt;p&gt;This is the Backup Flight System principle applied to a reconstruction: a bug in one implementation shouldn't be shared by the other. It is also the reason this project is the &lt;em&gt;easy&lt;/em&gt; arm of the series. An independent oracle is a luxury. Two of the other three don't have one, and the fourth has one deliberately sealed in an envelope.&lt;/p&gt;

&lt;h2&gt;
  
  
  What isn't there, on purpose
&lt;/h2&gt;

&lt;p&gt;The corpus is closed, and so is the scope. FIXED-point scaling, true mid-statement preemption in the real-time executive, the latched/unlatched event distinction, and full 56-bit hex DOUBLE are all unimplemented, each logged with its reasoning. Not because they're hard — because no preserved program exercises them, so there would be nothing to check the implementation against.&lt;/p&gt;

&lt;p&gt;Building unverifiable behaviour is the specific failure this project was structured to avoid. It is also the thing an eager model will happily do for you at any hour, which is why the constraint has to live in the repo rather than in your intentions.&lt;/p&gt;

&lt;p&gt;The payoff for all that discipline is &lt;a href="https://github.com/singular-state/space-shuttle-sdk/tree/main/crates/hals-wasm/web" rel="noopener noreferrer"&gt;Fly the Shuttle&lt;/a&gt;: the same interpreter compiled to WebAssembly, driving a landing simulator whose flight law is editable HAL/S. The hardcore vehicle writes the approach as actual flight software — a guidance &lt;code&gt;TASK&lt;/code&gt; that the real-time executive runs each cycle over &lt;code&gt;VECTOR&lt;/code&gt; state, terminated by a &lt;code&gt;TOUCHDOWN&lt;/code&gt; event. You can crash it by editing the autopilot, which is the correct relationship to have with a language like this.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the easy case actually proves
&lt;/h2&gt;

&lt;p&gt;Give a current model a formal spec, real code to test against, and an independent implementation to check answers with, and it will produce a faithful reconstruction of a dead language. That's the result, and it's a genuinely strong one.&lt;/p&gt;

&lt;p&gt;The load-bearing human contributions were smaller than expected and not where I expected. Not architecture, not algorithms, not debugging the type checker. They were: &lt;strong&gt;deciding not to vote between correlated OCR engines&lt;/strong&gt;, and &lt;strong&gt;reading 485 grammar productions against page images by eye&lt;/strong&gt;. One judgement call and one irreducible act of looking.&lt;/p&gt;

&lt;p&gt;The first is the kind of mistake that produces a clean-looking artifact with silent errors baked in, which is the worst failure shape available. The second is bounded by information theory rather than by model capability — no future model recovers a character the scan destroyed. Better OCR narrows that gap. It never closes it.&lt;/p&gt;

&lt;p&gt;Next in the series: the same question with the spec removed entirely. The source of truth is a novel, there is no oracle, so the project had to build one — and then discovered that Verne's submarine implodes at roughly 340 metres.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Code: &lt;a href="https://github.com/singular-state/space-shuttle-sdk" rel="noopener noreferrer"&gt;https://github.com/singular-state/space-shuttle-sdk&lt;/a&gt;. The HAL/S corpus and IR-542 are NASA-derived public domain, preserved by the Virtual AGC project, which also supplies the &lt;code&gt;yaHAL-S&lt;/code&gt; oracle. Transcription working artifacts — page renders, crops, per-engine output, per-page verified fragments — are committed under &lt;code&gt;transcription/&lt;/code&gt; so the grammar can be audited against the scan rather than taken on trust.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>rust</category>
      <category>nasa</category>
      <category>programming</category>
    </item>
    <item>
      <title>Your AI Coding Agent Just Finished. Now Ask It to Attack Its Own Work.</title>
      <dc:creator>Jean-Luc Martel</dc:creator>
      <pubDate>Fri, 21 Aug 2026 01:39:27 +0000</pubDate>
      <link>https://dev.to/jlmartel/your-ai-coding-agent-just-finished-now-ask-it-to-attack-its-own-work-54g3</link>
      <guid>https://dev.to/jlmartel/your-ai-coding-agent-just-finished-now-ask-it-to-attack-its-own-work-54g3</guid>
      <description>&lt;p&gt;AI coding agents are remarkably good at getting from “here’s what I want” to “here’s a working implementation.”&lt;/p&gt;

&lt;p&gt;They are also remarkably good at being satisfied with what they just built.&lt;/p&gt;

&lt;p&gt;That second trait is a problem.&lt;/p&gt;

&lt;p&gt;One of the highest-leverage habits I’ve picked up when working with coding agents is surprisingly simple:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;After the agent finishes a meaningful piece of work, ask it to perform an adversarial review of its own implementation.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Not:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Review your work and make sure everything looks good.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That tends to produce a polite little victory lap.&lt;/p&gt;

&lt;p&gt;Instead, change the objective.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Act as an adversarial reviewer. Assume this implementation contains subtle bugs, incorrect assumptions, security issues, race conditions, missing edge cases, or architectural problems. Your job is to find them. Do not defend the implementation. Try to break it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The difference can be dramatic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building and attacking are different tasks
&lt;/h2&gt;

&lt;p&gt;When an agent is implementing a feature, its working objective is roughly:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Find a plausible path to satisfying the requirements.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Once it has found that path, everything it sees is colored by the solution it just constructed.&lt;/p&gt;

&lt;p&gt;Humans do this too.&lt;/p&gt;

&lt;p&gt;You write a function, run the obvious tests, and your brain quietly becomes the function’s defense attorney.&lt;/p&gt;

&lt;p&gt;The code looks reasonable because you know what it was &lt;em&gt;supposed&lt;/em&gt; to do.&lt;/p&gt;

&lt;p&gt;An adversarial review gives the model a different role:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Assume the implementation is wrong. Find the evidence.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That changes what it searches for.&lt;/p&gt;

&lt;p&gt;Instead of asking:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Does this satisfy the happy path?&lt;/li&gt;
&lt;li&gt;Does this compile?&lt;/li&gt;
&lt;li&gt;Did I implement the requested feature?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;it starts asking:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What happens with malformed input?&lt;/li&gt;
&lt;li&gt;What assumption did I make that the caller never promised?&lt;/li&gt;
&lt;li&gt;What happens under concurrency?&lt;/li&gt;
&lt;li&gt;Is this operation actually atomic?&lt;/li&gt;
&lt;li&gt;Can this fail halfway through?&lt;/li&gt;
&lt;li&gt;What happens when a dependency returns something unexpected?&lt;/li&gt;
&lt;li&gt;Did I introduce an authorization bypass?&lt;/li&gt;
&lt;li&gt;Did I preserve existing behavior?&lt;/li&gt;
&lt;li&gt;Is there a hidden performance cliff?&lt;/li&gt;
&lt;li&gt;Are the tests proving the behavior, or merely exercising the implementation?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Same model. Same context. Very different search space.&lt;/p&gt;

&lt;h2&gt;
  
  
  The prompt I actually want
&lt;/h2&gt;

&lt;p&gt;Something like this works well:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Perform an adversarial review of the implementation you just created.

Assume there are bugs.

Do not explain why the current implementation is good. Your job is to attack it.

Look specifically for:

- incorrect assumptions
- edge cases
- race conditions
- security vulnerabilities
- data corruption risks
- failure/retry problems
- backwards compatibility issues
- performance regressions
- missing validation
- incorrect error handling
- tests that pass without proving the intended behavior

For every issue you find:

1. Describe the failure mode.
2. Explain how it could occur in practice.
3. Rate its severity.
4. Point to the relevant code.
5. Propose a concrete fix.

Do not modify the code yet. First produce the review.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That last instruction matters.&lt;/p&gt;

&lt;p&gt;I usually want the &lt;strong&gt;review before the repair&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If you immediately ask the agent to “find and fix any problems,” it can silently patch things while skipping the explanation. Separating diagnosis from remediation makes the reasoning inspectable.&lt;/p&gt;

&lt;p&gt;It also lets you decide which findings are real.&lt;/p&gt;

&lt;p&gt;Because the agent can absolutely invent problems too.&lt;/p&gt;

&lt;h2&gt;
  
  
  Make it argue against itself
&lt;/h2&gt;

&lt;p&gt;For larger changes, I sometimes push this further and create two explicit roles.&lt;/p&gt;

&lt;p&gt;First:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You are the implementation engineer. Complete the feature.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You are now a senior engineer reviewing this change before production deployment.

You did not write this code.

Assume the implementation engineer was competent but may have made subtle mistakes.

Try to reject this change.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The phrase &lt;strong&gt;“You did not write this code”&lt;/strong&gt; is surprisingly useful.&lt;/p&gt;

&lt;p&gt;Obviously the model did write it. We are not performing metaphysical surgery on the transformer.&lt;/p&gt;

&lt;p&gt;But role framing affects the kind of analysis the model performs. Removing psychological ownership, even fictitiously, tends to produce a more skeptical review.&lt;/p&gt;

&lt;p&gt;For especially important code, you can go further:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Imagine this change caused a production incident three months from now.

Work backwards and identify the most plausible ways this implementation could have caused it.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you’re effectively asking for a miniature pre-mortem.&lt;/p&gt;

&lt;p&gt;That often surfaces issues a generic code review misses.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ask for counterexamples, not opinions
&lt;/h2&gt;

&lt;p&gt;One of the easiest ways to make AI review more useful is to demand concrete failure cases.&lt;/p&gt;

&lt;p&gt;Bad:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Is this implementation robust?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Better:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Give me five concrete inputs, system states, or event sequences that could cause this implementation to behave incorrectly.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Even better:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;For each suspected bug, construct the smallest reproducible scenario that would demonstrate it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This forces the critique toward falsifiable claims.&lt;/p&gt;

&lt;p&gt;For example, instead of:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;There may be a race condition here.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;you want:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Request A reads balance=100. Request B reads balance=100. Both subtract 80. Both persist 20. The system has processed $160 of withdrawals from a $100 balance.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is something you can reason about.&lt;/p&gt;

&lt;p&gt;And test.&lt;/p&gt;

&lt;h2&gt;
  
  
  Turn the findings into tests
&lt;/h2&gt;

&lt;p&gt;This is where the workflow becomes particularly powerful.&lt;/p&gt;

&lt;p&gt;After the adversarial review, ask:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;For every credible issue you identified, write a regression test that fails against the current implementation.

Do not change the production code yet.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the loop becomes:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Implement → Attack → Reproduce → Repair → Verify&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That is much stronger than:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Implement → Looks good → Ship&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;And it makes the agent prove its criticism.&lt;/p&gt;

&lt;p&gt;If the supposed bug cannot be reproduced, maybe the review was wrong.&lt;/p&gt;

&lt;p&gt;If the test fails, you now have both evidence and permanent coverage.&lt;/p&gt;

&lt;h2&gt;
  
  
  Different reviewers find different classes of bugs
&lt;/h2&gt;

&lt;p&gt;“Review this code” is extremely underspecified.&lt;/p&gt;

&lt;p&gt;I get better results by running multiple targeted reviews.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;h3&gt;
  
  
  Security reviewer
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Review this implementation as a hostile application security engineer.

Look for ways an attacker could abuse inputs, authentication, authorization, state transitions, serialization, file access, network calls, or resource consumption.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Reliability reviewer
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Review this as a distributed systems reliability engineer.

Focus on partial failure, retries, duplicate execution, idempotency, ordering, timeouts, race conditions, stale state, and recovery after crashes.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  API reviewer
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Review this as the maintainer of clients that depend on this API.

Look for undocumented behavior changes, ambiguous contracts, backwards compatibility problems, surprising defaults, and error semantics.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Performance reviewer
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Assume this works correctly at 100 requests per day but fails badly at 10 million.

Find the scaling problems.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These prompts constrain the search.&lt;/p&gt;

&lt;p&gt;And constrained searches are often much better than asking a model to vaguely “think harder.”&lt;/p&gt;

&lt;h2&gt;
  
  
  There is another benefit: specification discovery
&lt;/h2&gt;

&lt;p&gt;The adversarial pass does something beyond finding implementation bugs.&lt;/p&gt;

&lt;p&gt;It often discovers that your &lt;strong&gt;requirements were incomplete&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Suppose the agent asks:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What should happen if two users update the object simultaneously?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Maybe you never specified that.&lt;/p&gt;

&lt;p&gt;Or:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Is deleting this resource supposed to cascade to associated records?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Also unspecified.&lt;/p&gt;

&lt;p&gt;Or:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Should this endpoint reveal whether an email address already exists?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Congratulations, your coding agent just wandered into a product/security decision disguised as an implementation detail.&lt;/p&gt;

&lt;p&gt;This is one of the more useful properties of adversarial review.&lt;/p&gt;

&lt;p&gt;It exposes the negative space around your specification.&lt;/p&gt;

&lt;p&gt;The original implementation task asks:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What did the user tell me to build?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The adversarial task asks:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What did the user forget to tell me?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That second question can be much more valuable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why not just ask it to “double-check”?
&lt;/h2&gt;

&lt;p&gt;Because “double-check” preserves the original frame.&lt;/p&gt;

&lt;p&gt;The model is still trying to validate the solution.&lt;/p&gt;

&lt;p&gt;Adversarial review changes the success criterion.&lt;/p&gt;

&lt;p&gt;Success is no longer:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The implementation appears correct.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Success becomes:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I found a credible way this could fail.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That small prompt-engineering shift matters.&lt;/p&gt;

&lt;p&gt;It is basically the software equivalent of red teaming.&lt;/p&gt;

&lt;p&gt;You don't ask the red team to confirm that the defenses look sensible.&lt;/p&gt;

&lt;p&gt;You tell them to get in.&lt;/p&gt;

&lt;h2&gt;
  
  
  Don't blindly accept the critique either
&lt;/h2&gt;

&lt;p&gt;There is an important caveat.&lt;/p&gt;

&lt;p&gt;AI-generated criticism is not automatically correct.&lt;/p&gt;

&lt;p&gt;A sufficiently determined model can find imaginary bugs with impressive confidence.&lt;/p&gt;

&lt;p&gt;So I treat adversarial findings as hypotheses.&lt;/p&gt;

&lt;p&gt;The hierarchy is roughly:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Concrete failing test&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reproducible execution path&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Clear reasoning from documented behavior&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Plausible concern&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Vibes wearing a security-engineer costume&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The farther down that list a finding sits, the less weight I give it.&lt;/p&gt;

&lt;p&gt;This is also why asking the agent to produce reproduction cases and tests is so useful.&lt;/p&gt;

&lt;p&gt;It converts prose into evidence.&lt;/p&gt;

&lt;h2&gt;
  
  
  Make the agent inspect the diff, not just its memory
&lt;/h2&gt;

&lt;p&gt;If your tool supports it, another useful instruction is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Review the actual git diff and all directly affected code.

Do not rely on your memory of what you intended to change.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Intent is dangerous during review.&lt;/p&gt;

&lt;p&gt;The implementation may not match the agent’s mental model of the implementation.&lt;/p&gt;

&lt;p&gt;The diff is reality.&lt;/p&gt;

&lt;p&gt;For significant changes, I also ask it to inspect neighboring code and call sites. Bugs frequently live at boundaries rather than inside the newly written function.&lt;/p&gt;

&lt;h2&gt;
  
  
  A workflow worth automating
&lt;/h2&gt;

&lt;p&gt;For meaningful changes, my preferred agent loop is increasingly something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. Understand the task.
2. Inspect the existing code.
3. Propose an implementation plan.
4. Implement the change.
5. Run relevant tests.
6. Perform an adversarial review.
7. Produce concrete failure cases for credible findings.
8. Add regression tests.
9. Fix confirmed issues.
10. Run the full relevant test suite.
11. Review the final diff again.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can put this directly into an agent instruction file.&lt;/p&gt;

&lt;p&gt;The marginal cost is tiny.&lt;/p&gt;

&lt;p&gt;The value can be enormous.&lt;/p&gt;

&lt;h2&gt;
  
  
  The broader lesson
&lt;/h2&gt;

&lt;p&gt;The interesting thing here isn't really the prompt.&lt;/p&gt;

&lt;p&gt;It's that AI coding agents become more useful when we stop treating them as a single programmer with a single continuous train of thought.&lt;/p&gt;

&lt;p&gt;They can be the implementer.&lt;/p&gt;

&lt;p&gt;Then the reviewer.&lt;/p&gt;

&lt;p&gt;Then the attacker.&lt;/p&gt;

&lt;p&gt;Then the test engineer.&lt;/p&gt;

&lt;p&gt;Then the maintainer wondering what lunatic wrote this six months ago.&lt;/p&gt;

&lt;p&gt;Those roles optimize for different things.&lt;/p&gt;

&lt;p&gt;And one of the cheapest ways to improve AI-generated software is to deliberately make the model disagree with the version of itself that wrote the code.&lt;/p&gt;

&lt;p&gt;So the next time your coding agent announces:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Implementation complete. All tests pass.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Don't congratulate it yet.&lt;/p&gt;

&lt;p&gt;Tell it to try to destroy what it just built.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>testing</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>How to Let gzip Find the Signal in a Pile of Documents</title>
      <dc:creator>Jean-Luc Martel</dc:creator>
      <pubDate>Mon, 03 Aug 2026 23:19:53 +0000</pubDate>
      <link>https://dev.to/jlmartel/how-to-let-gzip-find-the-signal-in-a-pile-of-documents-2o9g</link>
      <guid>https://dev.to/jlmartel/how-to-let-gzip-find-the-signal-in-a-pile-of-documents-2o9g</guid>
      <description>&lt;p&gt;Suppose you have a directory full of text documents.&lt;/p&gt;

&lt;p&gt;Most are repetitive, padded with boilerplate, or otherwise low-signal. A few contain the useful material. You could read every file manually, feed them all into an embedding pipeline, or ask an LLM to rank them.&lt;/p&gt;

&lt;p&gt;Or you could ask &lt;strong&gt;gzip&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The basic idea is simple:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Repetitive text compresses well. Varied text usually does not.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That makes compression ratio a crude but surprisingly useful proxy for redundancy.&lt;/p&gt;

&lt;p&gt;It will not tell you which document is &lt;em&gt;best&lt;/em&gt;. But it can help you identify which documents contain less repetition and deserve a closer look.&lt;/p&gt;

&lt;h2&gt;
  
  
  The heuristic
&lt;/h2&gt;

&lt;p&gt;For each document:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Measure its original size.&lt;/li&gt;
&lt;li&gt;Compress it individually with &lt;code&gt;gzip&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Measure the compressed size.&lt;/li&gt;
&lt;li&gt;Calculate:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;compressed size / original size
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A lower ratio means the document compressed well, which usually indicates more repetition.&lt;/p&gt;

&lt;p&gt;A higher ratio means the document was harder to compress, which may indicate more varied or information-dense content.&lt;/p&gt;

&lt;p&gt;In other words:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;lower ratio: more redundant&lt;/li&gt;
&lt;li&gt;higher ratio: less redundant&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Bash command
&lt;/h2&gt;

&lt;p&gt;Here is a small Bash pipeline that ranks &lt;code&gt;.txt&lt;/code&gt; files by compression ratio:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;find ./documents &lt;span class="nt"&gt;-type&lt;/span&gt; f &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s1"&gt;'*.txt'&lt;/span&gt; &lt;span class="nt"&gt;-print0&lt;/span&gt; |
&lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="nv"&gt;IFS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;read&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt; file&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
  &lt;/span&gt;&lt;span class="nv"&gt;raw&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;wc&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; &amp;lt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
  &lt;span class="nv"&gt;compressed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;gzip&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;wc&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

  &lt;span class="nb"&gt;awk&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="nv"&gt;file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="nv"&gt;raw&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$raw&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="nv"&gt;gz&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$compressed&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s1"&gt;'
    raw &amp;gt; 0 {
      printf "%.3f\t%8d\t%8d\t%s\n", gz/raw, raw, gz, file
    }
  '&lt;/span&gt;
&lt;span class="k"&gt;done&lt;/span&gt; | &lt;span class="nb"&gt;sort&lt;/span&gt; &lt;span class="nt"&gt;-nr&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0.642      18432      11834  ./documents/research-notes.txt
0.417      30211      12600  ./documents/project-summary.txt
0.091      27102       2467  ./documents/standard-contract.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The columns are:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ratio    original bytes    compressed bytes    filename
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because the output is sorted in descending order, the least compressible files appear first.&lt;/p&gt;

&lt;p&gt;Those are the files I would inspect first when looking for the possible “gems.”&lt;/p&gt;

&lt;p&gt;To find the most repetitive documents instead, reverse the sort:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sort&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why &lt;code&gt;gzip -n&lt;/code&gt;?
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;-n&lt;/code&gt; flag prevents &lt;code&gt;gzip&lt;/code&gt; from storing the original filename and timestamp in its output.&lt;/p&gt;

&lt;p&gt;That makes the compressed sizes more comparable across files and across runs.&lt;/p&gt;

&lt;p&gt;Without it, a small amount of unrelated metadata can leak into the measurement.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this is actually measuring
&lt;/h2&gt;

&lt;p&gt;This technique does not measure truth, relevance, writing quality, or semantic importance.&lt;/p&gt;

&lt;p&gt;It measures compressibility.&lt;/p&gt;

&lt;p&gt;Those things sometimes correlate, but they are not the same.&lt;/p&gt;

&lt;p&gt;A document full of repeated boilerplate will usually compress extremely well. A document with more distinct vocabulary, sentence structure, numbers, and ideas may compress less efficiently.&lt;/p&gt;

&lt;p&gt;That makes the ratio useful as a first-pass ranking signal.&lt;/p&gt;

&lt;p&gt;It is closer to a metal detector than a treasure map.&lt;/p&gt;

&lt;h2&gt;
  
  
  Important caveats
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Small files produce noisy ratios
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;gzip&lt;/code&gt; adds headers and other fixed overhead. For tiny files, that overhead can dominate the result.&lt;/p&gt;

&lt;p&gt;You may want to ignore documents below a minimum size:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;find ./documents &lt;span class="nt"&gt;-type&lt;/span&gt; f &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s1"&gt;'*.txt'&lt;/span&gt; &lt;span class="nt"&gt;-size&lt;/span&gt; +1k &lt;span class="nt"&gt;-print0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Already-compressed formats will mislead you
&lt;/h3&gt;

&lt;p&gt;Running this directly against PDF, DOCX, ZIP, JPG, or other compressed formats mostly measures the compression characteristics of the container format.&lt;/p&gt;

&lt;p&gt;Extract the text first.&lt;/p&gt;

&lt;p&gt;For example, with PDFs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pdftotext input.pdf output.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Incompressible does not mean valuable
&lt;/h3&gt;

&lt;p&gt;Encrypted data, random identifiers, hashes, minified code, and corrupted text are all difficult to compress.&lt;/p&gt;

&lt;p&gt;They may score highly while containing little useful information.&lt;/p&gt;

&lt;h3&gt;
  
  
  Repetition is not always fluff
&lt;/h3&gt;

&lt;p&gt;Contracts, API documentation, technical specifications, and scientific papers may repeat terminology because precision requires it.&lt;/p&gt;

&lt;p&gt;A lower ratio can indicate redundancy, but it can also indicate consistency.&lt;/p&gt;

&lt;h3&gt;
  
  
  Language and formatting matter
&lt;/h3&gt;

&lt;p&gt;Compression ratios can be affected by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;document length&lt;/li&gt;
&lt;li&gt;whitespace&lt;/li&gt;
&lt;li&gt;markup&lt;/li&gt;
&lt;li&gt;tables&lt;/li&gt;
&lt;li&gt;repeated headings&lt;/li&gt;
&lt;li&gt;source language&lt;/li&gt;
&lt;li&gt;character encoding&lt;/li&gt;
&lt;li&gt;templated metadata&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For a fairer comparison, normalize the documents first.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;tr&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="s1"&gt;'[:space:]'&lt;/span&gt; &lt;span class="s1"&gt;' '&lt;/span&gt; &amp;lt; input.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You could also strip HTML, remove headers and footers, or convert everything to lowercase before compression.&lt;/p&gt;

&lt;p&gt;Just remember that normalization changes what you are measuring.&lt;/p&gt;

&lt;h2&gt;
  
  
  A slightly more useful version
&lt;/h2&gt;

&lt;p&gt;For larger collections, I would filter out tiny files and print the percentage saved:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;find ./documents &lt;span class="nt"&gt;-type&lt;/span&gt; f &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s1"&gt;'*.txt'&lt;/span&gt; &lt;span class="nt"&gt;-size&lt;/span&gt; +1k &lt;span class="nt"&gt;-print0&lt;/span&gt; |
&lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="nv"&gt;IFS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;read&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt; file&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
  &lt;/span&gt;&lt;span class="nv"&gt;raw&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;wc&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; &amp;lt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
  &lt;span class="nv"&gt;compressed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;gzip&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;wc&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

  &lt;span class="nb"&gt;awk&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="nv"&gt;file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="nv"&gt;raw&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$raw&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="nv"&gt;gz&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$compressed&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s1"&gt;'
    raw &amp;gt; 0 {
      ratio = gz / raw
      saved = 100 * (1 - ratio)

      printf "%6.2f%% saved\t%8d bytes\t%s\n",
             saved, raw, file
    }
  '&lt;/span&gt;
&lt;span class="k"&gt;done&lt;/span&gt; | &lt;span class="nb"&gt;sort&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This sorts the files with the lowest percentage saved first, meaning the least compressible documents rise to the top.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where this could be useful
&lt;/h2&gt;

&lt;p&gt;This trick can be handy for quickly triaging:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;scraped web pages&lt;/li&gt;
&lt;li&gt;exported support tickets&lt;/li&gt;
&lt;li&gt;meeting transcripts&lt;/li&gt;
&lt;li&gt;research notes&lt;/li&gt;
&lt;li&gt;log samples&lt;/li&gt;
&lt;li&gt;generated reports&lt;/li&gt;
&lt;li&gt;document archives&lt;/li&gt;
&lt;li&gt;large sets of Markdown files&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is especially useful when you want a fast local heuristic without setting up a database, embedding model, or external API.&lt;/p&gt;

&lt;h2&gt;
  
  
  Compression as a feature
&lt;/h2&gt;

&lt;p&gt;The broader idea is more interesting than the Bash command.&lt;/p&gt;

&lt;p&gt;Compression ratio can be treated as a lightweight feature in a ranking system.&lt;/p&gt;

&lt;p&gt;You could combine it with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;document length&lt;/li&gt;
&lt;li&gt;vocabulary diversity&lt;/li&gt;
&lt;li&gt;duplicate paragraph counts&lt;/li&gt;
&lt;li&gt;keyword density&lt;/li&gt;
&lt;li&gt;entropy&lt;/li&gt;
&lt;li&gt;embedding similarity&lt;/li&gt;
&lt;li&gt;recency&lt;/li&gt;
&lt;li&gt;source reputation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Compression alone is crude.&lt;/p&gt;

&lt;p&gt;Compression plus a few other signals could become a genuinely useful document-triage tool.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final thought
&lt;/h2&gt;

&lt;p&gt;There are sophisticated ways to rank a pile of documents.&lt;/p&gt;

&lt;p&gt;Sometimes, though, a 40-year-old compression algorithm is enough to tell you which files keep repeating themselves.&lt;/p&gt;

&lt;p&gt;And that is often a very good place to start.&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>automation</category>
      <category>bash</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
