<?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>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>
