<?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: Malek AIT OUARET</title>
    <description>The latest articles on DEV Community by Malek AIT OUARET (@malek_aitouaret_f026758c).</description>
    <link>https://dev.to/malek_aitouaret_f026758c</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%2F4192110%2F3f472050-c40f-4442-900a-f7ab6bf0cf24.png</url>
      <title>DEV Community: Malek AIT OUARET</title>
      <link>https://dev.to/malek_aitouaret_f026758c</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/malek_aitouaret_f026758c"/>
    <language>en</language>
    <item>
      <title>A compiler that refuses a contract that says too little</title>
      <dc:creator>Malek AIT OUARET</dc:creator>
      <pubDate>Wed, 11 Nov 2026 12:30:36 +0000</pubDate>
      <link>https://dev.to/malek_aitouaret_f026758c/a-compiler-that-refuses-a-contract-that-says-too-little-5521</link>
      <guid>https://dev.to/malek_aitouaret_f026758c/a-compiler-that-refuses-a-contract-that-says-too-little-5521</guid>
      <description>&lt;h1&gt;
  
  
  A compiler that refuses a contract that says too little
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;This article was written with the help of an AI assistant (Claude), like the language it describes, which was built with Claude Code. I checked every figure against the repository and I take responsibility for the content. It follows &lt;a href="https://dev.to/malek_aitouaret_f026758c/green-proofs-empty-promises-when-ai-agents-write-their-own-specifications-59lf"&gt;Green proofs, empty promises&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  A green proof that proves little
&lt;/h2&gt;

&lt;p&gt;In my previous article I asked a small model to write verified Dafny. The proofs were green. But 5 of the 8 contracts barely constrained the result: a length, a format, a shape. One of those methods was wrong, and the proof did not notice.&lt;/p&gt;

&lt;p&gt;A verifier proves what it is asked to prove. If the same agent writes the code and its contract, it can ask for exactly as much as it manages to prove. Checking the &lt;em&gt;proof&lt;/em&gt; is not enough; the question is whether the &lt;em&gt;contract&lt;/em&gt; says enough.&lt;/p&gt;

&lt;h2&gt;
  
  
  The idea
&lt;/h2&gt;

&lt;p&gt;I built a small language, Quod, to try one rule: &lt;strong&gt;the compiler asks whether two different results could both satisfy the contract.&lt;/strong&gt; If so, it refuses the program and shows you the two results.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dafny"&gt;&lt;code&gt;&lt;span class="n"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;clamp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hi&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
  &lt;span class="n"&gt;requires&lt;/span&gt; &lt;span class="n"&gt;lo&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;hi&lt;/span&gt;
  &lt;span class="n"&gt;ensures&lt;/span&gt; &lt;span class="n"&gt;lo&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;hi&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;lo&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;lo&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;hi&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;hi&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;x&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ quod check clamp_weak.quod
error: in clamp: the contract accepts two different results for the same input:
add ensures clauses until only the intended result is allowed, or declare the freedom with 'loose'
    witness: x = 0, lo = 0, hi = 1, result_a = 1, result_b = 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For &lt;code&gt;x = 0&lt;/code&gt; in &lt;code&gt;[0, 1]&lt;/code&gt;, both &lt;code&gt;0&lt;/code&gt; (the right answer) and &lt;code&gt;1&lt;/code&gt; satisfy the contract. This is a contract that a verifier would accept with a green proof, because &lt;code&gt;clamp&lt;/code&gt; does stay within &lt;code&gt;[lo, hi]&lt;/code&gt;. Here is what it was missing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dafny"&gt;&lt;code&gt;  &lt;span class="n"&gt;ensures&lt;/span&gt; &lt;span class="n"&gt;lo&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;hi&lt;/span&gt;
  &lt;span class="n"&gt;ensures&lt;/span&gt; &lt;span class="n"&gt;lo&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;hi&lt;/span&gt; &lt;span class="o"&gt;==&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;
  &lt;span class="n"&gt;ensures&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;lo&lt;/span&gt; &lt;span class="o"&gt;==&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;lo&lt;/span&gt;
  &lt;span class="n"&gt;ensures&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;hi&lt;/span&gt; &lt;span class="o"&gt;==&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;hi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;verified: 4 proof obligation(s) proved; 1 of 1 contract(s) determine their result; contracts: 1 by properties
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two things keep this from being a trick:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;You cannot cheat by copying the body.&lt;/strong&gt; A contract that just restates the code is complete, so the compiler reports the &lt;em&gt;style&lt;/em&gt; of every contract (properties, model, restated, missing) and warns when it is only a restatement. In my first experiments, 4 of 6 agent-written contracts defined the result with a second implementation, and this is what the warning is for.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Freedom can be declared, but it is watched.&lt;/strong&gt; If several results are really acceptable (any index of a duplicate in a binary search), you write &lt;code&gt;loose (a, b) =&amp;gt; ...&lt;/code&gt; with what the two results must have in common, and the compiler shows an example. A &lt;code&gt;loose&lt;/code&gt; that holds for any two results is reported as proving nothing, and can be refused outright.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Everything else is classic: contracts, loop invariants and termination are proved with Z3, which ships in the release package. The check itself is a satisfiability question: do the preconditions and two different results, both allowed by the postconditions, have a solution? When the solver cannot decide, the check only warns, so "refuses" means "refuses when it can tell".&lt;/p&gt;

&lt;h2&gt;
  
  
  What exists
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Pure functions with contracts, lemmas, modules, strings, bounded integers (&lt;code&gt;i32&lt;/code&gt;, &lt;code&gt;i64&lt;/code&gt;), structs, enums, &lt;code&gt;match&lt;/code&gt; and generics.&lt;/li&gt;
&lt;li&gt;A Python backend, and a C# backend (C# 7.3, so it also targets .NET Framework 4.7.2). The C# for &lt;code&gt;clamp&lt;/code&gt; is what you would write:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="nc"&gt;Clamp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;lo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;hi&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lo&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;hi&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ArgumentException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"clamp: requires lo &amp;lt;= hi"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;_quod_f_clamp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hi&lt;/span&gt;&lt;span class="p"&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;Quod's &lt;code&gt;int&lt;/code&gt; is a &lt;code&gt;long&lt;/code&gt; computed in &lt;code&gt;checked&lt;/code&gt;: an overflow throws rather than returns a wrong result. &lt;code&gt;i32&lt;/code&gt; and &lt;code&gt;i64&lt;/code&gt; have their bounds proved. I have not measured the speed of the generated C#.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An MCP server (&lt;code&gt;quod mcp&lt;/code&gt;), so that an agent can write, check and correct in a loop, and a NuGet package (attached to the releases, not on nuget.org) that generates the C# at build time. z3 comes in the release archive, so a CI job only downloads it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Today it is limited to pure functions: no input or output, no maps or sets, yet. Input and output are planned, as capabilities (a function touches the console, files or the network only through a capability it receives, so the contract still says what it may do), together with maps and sets: it is the next item of the roadmap. There are no classes and none are planned; structs, enums and generics cover the data. You call a Quod function from Python or C#.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I measured
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Agents can write programs of a useful size in it.&lt;/strong&gt; Two models wrote billing engines of about 300 lines over three modules, from the language reference alone. All 24 runs verified and agreed with an oracle. The rules, the oracle and the compiler have one author, so this shows the tool works on one kind of program; it does not show that the test was hard.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;With a capable model, the rule did not change the number of complete contracts.&lt;/strong&gt; I measured no gain. My reading: a capable model already writes contracts that fix the result, so the rule works as a guardrail for the reviewer, not as a teacher for the model.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Against Dafny, my soundness measure could not tell the two apart&lt;/strong&gt; on 72 held-out runs (four setups, six tasks, a small model). I can claim a different design and a different workflow, not better soundness.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A small model is not helped by the message.&lt;/strong&gt; A 14B local model got 0 of 18 accepted, mostly stuck on syntax it had learned from Dafny. The error for a missing contract does not teach it to write one.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A complete contract can still be the wrong one.&lt;/strong&gt; One run produced &lt;code&gt;ensures len(result) == 0&lt;/code&gt; over &lt;code&gt;return []&lt;/code&gt;. The rule asks whether the contract fixes the result, not whether it is the result you meant. A human still has to read the contracts, which is why the compiler lists the ones to review.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What the proofs are worth
&lt;/h2&gt;

&lt;p&gt;Several adversarial reviews, by a language model told to attack the compiler with programs that can be replayed, found real problems, and I fixed all of them. Two kinds:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;False proofs&lt;/strong&gt;: a length axiom that was too strong, a loop helper called without its precondition, and z3 answering &lt;code&gt;unsat&lt;/code&gt; to a satisfiable question after an interrupted check. I saw the last one as wrongly refused builds, about 1 in 300 on one family of files (&lt;a href="https://github.com/quod-lang/quod/releases/tag/v0.1.8" rel="noopener noreferrer"&gt;release notes&lt;/a&gt;); a proof rests on the same answer, so I treated it as a risk to proofs and looked for false proofs afterwards, without finding one.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Generated code that contradicted a proof&lt;/strong&gt;: a Python variable that hid a class, and, in C#, two modules whose names differ only by case, &lt;code&gt;a_b&lt;/code&gt; and &lt;code&gt;aB&lt;/code&gt;, that became one class.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The last review, of 0.4.0, found no false proof and no such contradiction in the default build. I do not claim none is left. One known limit: with a time budget (&lt;code&gt;--budget&lt;/code&gt;), which obligations are cut can depend on the speed of the machine.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where it stands against what I know
&lt;/h2&gt;

&lt;p&gt;Completeness of generated specifications has been studied: Lahiri (2024) scored LLM-generated Dafny postconditions by whether they reject mutated outputs, and VeriEquivBench (2025) proves specifications equivalent to the code (I have read only part of that paper). Both measure after the fact. The experiment here is to put the question in the compiler, where the agent reads the answer while it writes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it, and tell me where it was hard
&lt;/h2&gt;

&lt;p&gt;Almost nobody but me has used Quod. That is the real gap, more than any missing feature.&lt;/p&gt;

&lt;p&gt;There is a &lt;a href="https://github.com/quod-lang/quod#install-and-try" rel="noopener noreferrer"&gt;30-minute path&lt;/a&gt;: download a release (Windows, Linux or macOS; z3 is inside), check an example, read the error of the weak contract, generate Python and C#, and write a small function of your own. Then tell me where you got stuck, using &lt;a href="https://github.com/quod-lang/quod/discussions/categories/first-try" rel="noopener noreferrer"&gt;this short form&lt;/a&gt;. "I gave up at step 2, because..." is a perfectly good report.&lt;/p&gt;

&lt;p&gt;If you read C#, I am especially interested in the generated code. I have written C# for more than twenty years and judge it by reading it, and I would like to know whether it looks normal to someone else.&lt;/p&gt;

&lt;p&gt;Repository: &lt;a href="https://github.com/quod-lang/quod" rel="noopener noreferrer"&gt;https://github.com/quod-lang/quod&lt;/a&gt;&lt;/p&gt;

</description>
      <category>programming</category>
      <category>ai</category>
      <category>dotnet</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Green proofs, empty promises: when AI agents write their own specifications</title>
      <dc:creator>Malek AIT OUARET</dc:creator>
      <pubDate>Wed, 21 Oct 2026 07:44:35 +0000</pubDate>
      <link>https://dev.to/malek_aitouaret_f026758c/green-proofs-empty-promises-when-ai-agents-write-their-own-specifications-59lf</link>
      <guid>https://dev.to/malek_aitouaret_f026758c/green-proofs-empty-promises-when-ai-agents-write-their-own-specifications-59lf</guid>
      <description>&lt;p&gt;I asked AI coding agents to write &lt;strong&gt;formally verified&lt;/strong&gt; code. Every solution passed the&lt;br&gt;
verifier. Then I checked what the proofs actually promised.&lt;/p&gt;

&lt;p&gt;For the smaller model, &lt;strong&gt;5 of 8 specifications barely said anything&lt;/strong&gt;. One of the&lt;br&gt;
methods was wrong, and its proof was green.&lt;/p&gt;

&lt;p&gt;This post is about that gap, a cheap way to detect it, and a small open-source tool that does it&lt;br&gt;
for any Dafny file.&lt;/p&gt;
&lt;h2&gt;
  
  
  The experiment
&lt;/h2&gt;

&lt;p&gt;I'm designing a programming language meant to be written by agents and checked by machines&lt;br&gt;
(more on that at the end). Before designing anything, I wanted data: &lt;strong&gt;when an agent has to prove&lt;br&gt;
its code, do fewer bugs slip through?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The setup (&lt;a href="https://github.com/quod-lang/quod/tree/main/bench" rel="noopener noreferrer"&gt;VerifBench&lt;/a&gt;):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;8 short algorithmic tasks chosen because LLMs classically stumble on them: Gregorian
day counting (leap centuries), strict UTF-8 validation (overlongs, surrogates), glob matching
with escapes, an LRU cache, a lexicographically smallest topological sort, text justification,
big-number addition (borrows, &lt;code&gt;-0&lt;/code&gt;), Unix path normalization.&lt;/li&gt;
&lt;li&gt;Same natural-language spec, two arms: plain &lt;strong&gt;Python&lt;/strong&gt; (the agent may run its own tests), or
&lt;strong&gt;Dafny&lt;/strong&gt;, where the agent must write &lt;code&gt;requires&lt;/code&gt; / &lt;code&gt;ensures&lt;/code&gt; / invariants and get
&lt;code&gt;dafny verify&lt;/code&gt; to pass. Cheats like &lt;code&gt;assume&lt;/code&gt; or &lt;code&gt;{:verify false}&lt;/code&gt; are detected.&lt;/li&gt;
&lt;li&gt;Claude Code as the agent, two models: &lt;code&gt;claude-opus-5-5&lt;/code&gt; and &lt;code&gt;claude-haiku-4-5&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;About 500 &lt;strong&gt;hidden tests&lt;/strong&gt; per task, compared with an oracle. The Dafny code is compiled to
Python and goes through exactly the same tests.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The key metric is the &lt;strong&gt;escaped bug&lt;/strong&gt;: a solution the agent would ship (and, in Dafny, that&lt;br&gt;
verifies) which still fails a hidden test.&lt;/p&gt;
&lt;h2&gt;
  
  
  The results look reassuring...
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Model / arm&lt;/th&gt;
&lt;th&gt;Escaped bugs&lt;/th&gt;
&lt;th&gt;Cost per task*&lt;/th&gt;
&lt;th&gt;Time per task&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Opus / Python&lt;/td&gt;
&lt;td&gt;0 / 8&lt;/td&gt;
&lt;td&gt;$0.14&lt;/td&gt;
&lt;td&gt;17 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Opus / Dafny&lt;/td&gt;
&lt;td&gt;0 / 8&lt;/td&gt;
&lt;td&gt;$0.22&lt;/td&gt;
&lt;td&gt;46 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Haiku / Python&lt;/td&gt;
&lt;td&gt;1 / 8&lt;/td&gt;
&lt;td&gt;$0.15&lt;/td&gt;
&lt;td&gt;106 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Haiku / Dafny&lt;/td&gt;
&lt;td&gt;1 / 8&lt;/td&gt;
&lt;td&gt;$0.45&lt;/td&gt;
&lt;td&gt;255 s&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;small&gt;* API-equivalent estimate reported by the agent. One trial per cell: signals, not statistics.&lt;/small&gt;&lt;/p&gt;

&lt;p&gt;Opus solved everything, with or without proofs. Haiku let one bug through in each arm. Proof&lt;br&gt;
looks like it costs 1.5–3× more and buys... nothing here?&lt;/p&gt;
&lt;h2&gt;
  
  
  ...until you read the Haiku Dafny bug
&lt;/h2&gt;

&lt;p&gt;The escaped Dafny bug was in the LRU cache. The method &lt;strong&gt;verified&lt;/strong&gt;. Here is its signature&lt;br&gt;
(preconditions abridged) and its entire postcondition:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dafny"&gt;&lt;code&gt;&lt;span class="kr"&gt;method&lt;/span&gt; &lt;span class="n"&gt;lru_cache&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;capacity&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ops&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;seq&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kr"&gt;returns&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;seq&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kr"&gt;requires&lt;/span&gt; &lt;span class="n"&gt;capacity&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
  &lt;span class="kr"&gt;ensures&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;CountGets&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ops&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;ops&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output has the right &lt;em&gt;length&lt;/em&gt;. Nothing says which values a &lt;code&gt;get&lt;/code&gt; returns. The code evicted&lt;br&gt;
an entry every time a new key was inserted, whether the cache was full or not, and Dafny was&lt;br&gt;
perfectly happy, because nothing in the contract forbade it.&lt;/p&gt;

&lt;p&gt;A verifier only guarantees what you ask it to. And when the agent writes &lt;strong&gt;both&lt;/strong&gt; the code and&lt;br&gt;
the specification, it can, without any malice, ask for exactly as much as it manages to prove.&lt;/p&gt;

&lt;p&gt;So I went back and checked all 24 Dafny contracts.&lt;/p&gt;
&lt;h2&gt;
  
  
  A simple question to ask a specification
&lt;/h2&gt;

&lt;p&gt;For a method with precondition &lt;code&gt;R&lt;/code&gt; and postcondition &lt;code&gt;E&lt;/code&gt;, ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Can two &lt;strong&gt;different&lt;/strong&gt; results both satisfy &lt;code&gt;E&lt;/code&gt;, for the same valid input?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If the contract is complete, the answer is no:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ocl"&gt;&lt;code&gt;&lt;span class="err"&gt;∀&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="n"&gt;R&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;∧&lt;/span&gt; &lt;span class="n"&gt;E&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;∧&lt;/span&gt; &lt;span class="n"&gt;E&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="err"&gt;⇒&lt;/span&gt;  &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a question about the &lt;strong&gt;contract only&lt;/strong&gt;, not the code. And Dafny can answer it: generate&lt;br&gt;
a lemma with exactly that statement and ask Dafny to prove it, with no hints.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dafny"&gt;&lt;code&gt;&lt;span class="kr"&gt;ghost&lt;/span&gt; &lt;span class="kr"&gt;predicate&lt;/span&gt; &lt;span class="n"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;capacity&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ops&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;seq&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;seq&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kr"&gt;requires&lt;/span&gt; &lt;span class="n"&gt;capacity&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;CountGets&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ops&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;ops&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kr"&gt;lemma&lt;/span&gt; &lt;span class="n"&gt;Uniq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;capacity&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ops&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;seq&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;seq&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;seq&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kr"&gt;requires&lt;/span&gt; &lt;span class="n"&gt;capacity&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;capacity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ops&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;capacity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ops&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kr"&gt;ensures&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
&lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the proof goes through, the contract determines the result. When it fails, that may mean&lt;br&gt;
the contract is incomplete... or just that the uniqueness proof is hard (it often needs&lt;br&gt;
induction). To tell the two apart, you need a &lt;strong&gt;witness&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Finding witnesses
&lt;/h2&gt;

&lt;p&gt;The trick: take small concrete inputs, &lt;strong&gt;run the method&lt;/strong&gt; to get its actual answer &lt;code&gt;a&lt;/code&gt;, build&lt;br&gt;
neighbouring answers &lt;code&gt;b&lt;/code&gt; (a changed digit, a dropped element, an emptied list...), and ask Dafny&lt;br&gt;
to &lt;em&gt;prove&lt;/em&gt; that the contract accepts both &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt; on those concrete values.&lt;/p&gt;

&lt;p&gt;If both proofs go through, you have a certain witness: no sampling, no guessing. Results on the&lt;br&gt;
24 agent-written contracts:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Verdict&lt;/th&gt;
&lt;th&gt;Count&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Uniqueness proved&lt;/td&gt;
&lt;td&gt;15&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Underspecified, with a witness&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Inconclusive&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The six witnesses:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;Input&lt;/th&gt;
&lt;th&gt;Two results the contract accepts&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;add_big&lt;/code&gt; (Haiku)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;"0" + "0"&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;"0"&lt;/code&gt; and &lt;code&gt;"1"&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;topo_sort&lt;/code&gt; (Haiku)&lt;/td&gt;
&lt;td&gt;1 node, no edge&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;[0]&lt;/code&gt; and &lt;code&gt;[]&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;normalize_path&lt;/code&gt; (Haiku)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;""&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;"."&lt;/code&gt; and &lt;code&gt;".x"&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;justify&lt;/code&gt; (Haiku)&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;["a"]&lt;/code&gt;, width 2&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;["a "]&lt;/code&gt; and &lt;code&gt;[]&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;lru_cache&lt;/code&gt; (Haiku)&lt;/td&gt;
&lt;td&gt;two &lt;code&gt;get&lt;/code&gt;s on an empty cache&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;[-1, -1]&lt;/code&gt; and &lt;code&gt;[0, -1]&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;binary_search&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;[1, 1]&lt;/code&gt;, target 1&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;1&lt;/code&gt; and &lt;code&gt;0&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Read them as sentences and they speak for themselves: according to its proved contract, the&lt;br&gt;
addition is allowed to say 0 + 0 = 1. The topological sort may return nothing for a graph with&lt;br&gt;
no edge. The path normalizer may return any non-empty string.&lt;/p&gt;

&lt;p&gt;The last one, &lt;code&gt;binary_search&lt;/code&gt;, is &lt;strong&gt;legitimately&lt;/strong&gt; free: with duplicates, any index of the target&lt;br&gt;
is a correct answer. A witness doesn't mean "bug"; it means "the contract allows a choice", and&lt;br&gt;
someone should decide whether that choice is intended.&lt;/p&gt;

&lt;p&gt;The striking part: &lt;strong&gt;four of Haiku's five near-empty contracts sat on correct code&lt;/strong&gt;. The tests&lt;br&gt;
passed, the proofs were green, and the proofs guaranteed almost nothing. Without this check,&lt;br&gt;
"verified" on those methods was pure decoration.&lt;/p&gt;

&lt;p&gt;And the three inconclusive ones? I read them: their contracts &lt;em&gt;are&lt;/em&gt; complete (merging intervals&lt;br&gt;
into a canonical union, run-length encoding, canonical decimal strings), but proving uniqueness&lt;br&gt;
needs induction that the solver won't find alone. No witness was found for any of them, so the&lt;br&gt;
tool never reported them as underspecified. Clean separation, on this small sample.&lt;/p&gt;

&lt;p&gt;Opus, for the record, wrote contracts that were proved unique in 7 of 8 hard tasks, including a&lt;br&gt;
full lexicographic-minimality specification for the topological sort.&lt;/p&gt;
&lt;h2&gt;
  
  
  The tool: dafny-complete
&lt;/h2&gt;

&lt;p&gt;I turned this into a standalone checker that works on any &lt;code&gt;.dfy&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pipx &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="s2"&gt;"git+https://github.com/quod-lang/quod#subdirectory=tools/dafny-complete"&lt;/span&gt;
dafny-complete my_file.dfy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  [OK]    Abs      line 11    the contract determines a unique result
  [UNDER] WeakAbs  line 19    the contract accepts two different results
                    input  : x=0
                    y = 0   (what the method returns)
                    y = 1   (also satisfies every ensures)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It runs four Dafny passes over the whole file (uniqueness lemmas, valid small inputs proved&lt;br&gt;
against the preconditions, actual execution of the methods, witness lemmas) and never modifies&lt;br&gt;
your file. Exit code 1 when something is underspecified, so it can sit in CI, or in an agent's&lt;br&gt;
loop: &lt;code&gt;--json&lt;/code&gt; gives the witness in machine-readable form, which is exactly the feedback an agent&lt;br&gt;
needs to strengthen its contract.&lt;/p&gt;

&lt;p&gt;Without access to the benchmark's oracle, it reproduces all 24 verdicts. Run on the whole&lt;br&gt;
&lt;code&gt;add_big&lt;/code&gt; file rather than just the main method, it also flags the three helpers Haiku wrote&lt;br&gt;
(&lt;code&gt;AddAbsolute&lt;/code&gt; accepts &lt;code&gt;"10" + "10" = "201"&lt;/code&gt;): the weakness was not one slip, but the way the&lt;br&gt;
whole file was specified.&lt;/p&gt;
&lt;h2&gt;
  
  
  Limitations, honestly
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Small sample.&lt;/strong&gt; 8 tasks per suite, one trial per cell, one agent family. The pattern is
vivid, but it is a signal, not a measurement.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Complete is not correct.&lt;/strong&gt; A contract can pin down a single, wrong result. The check
removes specifications that are too &lt;em&gt;weak&lt;/em&gt;, not ones that are &lt;em&gt;mistaken&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The second-program trap.&lt;/strong&gt; A postcondition like &lt;code&gt;out == Model(ops)&lt;/code&gt;, where &lt;code&gt;Model&lt;/code&gt;
reimplements the problem, is always "complete", and can carry the same bug as the code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Witness search is heuristic.&lt;/strong&gt; Neighbours come from simple rules; a contract can be
incomplete in a subtler way and come out "inconclusive". Supported types for witnesses: &lt;code&gt;int&lt;/code&gt;,
&lt;code&gt;nat&lt;/code&gt;, &lt;code&gt;bool&lt;/code&gt;, &lt;code&gt;char&lt;/code&gt;, &lt;code&gt;string&lt;/code&gt;, &lt;code&gt;seq&amp;lt;T&amp;gt;&lt;/code&gt;, tuples. Instance methods and heap-touching methods
are skipped for now.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Prior work
&lt;/h2&gt;

&lt;p&gt;After publishing, I did the literature pass I should have done before. The core idea is not new:&lt;br&gt;
Shuvendu Lahiri's &lt;a href="https://arxiv.org/abs/2406.09757" rel="noopener noreferrer"&gt;Evaluating LLM-driven User-Intent Formalization for Verification-Aware Languages&lt;/a&gt;&lt;br&gt;
(FMCAD 2024) already tests Dafny specifications symbolically, scoring their completeness by&lt;br&gt;
mutating expected outputs on test cases and checking that the verifier rejects them. Related lines&lt;br&gt;
of work include &lt;a href="https://arxiv.org/abs/2310.01831" rel="noopener noreferrer"&gt;nl2postcond&lt;/a&gt; (completeness of LLM-written&lt;br&gt;
postconditions measured against code mutants), &lt;a href="https://arxiv.org/abs/2310.17807" rel="noopener noreferrer"&gt;Clover&lt;/a&gt;&lt;br&gt;
(consistency between code, docstrings and Dafny annotations), and Lahiri's 2026&lt;br&gt;
&lt;a href="https://arxiv.org/abs/2603.17150" rel="noopener noreferrer"&gt;intent-formalization agenda&lt;/a&gt;, which names validating&lt;br&gt;
specifications as the central bottleneck for AI-written code. Weak or vacuous specifications are&lt;br&gt;
also a documented failure mode in recent verified-code benchmarks.&lt;/p&gt;

&lt;p&gt;What &lt;code&gt;dafny-complete&lt;/code&gt; adds is modest: it needs no tests or reference code (it runs the method&lt;br&gt;
itself), it first tries a universal uniqueness proof, and it only reports a witness when Dafny&lt;br&gt;
proves the contract accepts it. Details in the repo's&lt;br&gt;
&lt;a href="https://github.com/quod-lang/quod/blob/main/docs/related-work.md" rel="noopener noreferrer"&gt;related-work note&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why I care: Quod
&lt;/h2&gt;

&lt;p&gt;This started as Phase 0 of &lt;a href="https://github.com/quod-lang/quod" rel="noopener noreferrer"&gt;Quod&lt;/a&gt;, a language designed to be&lt;br&gt;
written by AI agents and checked by machines. The bet: everything that is expensive for humans&lt;br&gt;
(exhaustive contracts, invariants, declared effects) is nearly free for an agent, so a language&lt;br&gt;
can demand it.&lt;/p&gt;

&lt;p&gt;This experiment changed the design. In Quod, the completeness check is built into the compiler:&lt;br&gt;
an underspecified function &lt;strong&gt;does not compile&lt;/strong&gt;, and the error comes with the witness. When&lt;br&gt;
several answers are legitimately acceptable, you say so explicitly, with a relation between two&lt;br&gt;
acceptable results:&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;fn&lt;/span&gt; &lt;span class="nf"&gt;binary_search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;xs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;i64&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;i64&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;Option&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;usize&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="n"&gt;requires&lt;/span&gt; &lt;span class="nf"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;xs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;ensures&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;
  &lt;span class="nf"&gt;loose&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r2&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;r1&lt;/span&gt;&lt;span class="nf"&gt;.is_some&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;r2&lt;/span&gt;&lt;span class="nf"&gt;.is_some&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;   &lt;span class="c1"&gt;// which index may vary; found/not found may not&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Freedom becomes a visible, checked decision instead of an oversight.&lt;/p&gt;

&lt;p&gt;Everything is open: the benchmark with every agent transcript, the language draft, and the tool&lt;br&gt;
(Apache 2.0). If you write Dafny, I'd love to know what &lt;code&gt;dafny-complete&lt;/code&gt; finds, or misses, on&lt;br&gt;
your code. Issues and discussions are open at&lt;br&gt;
&lt;a href="https://github.com/quod-lang/quod" rel="noopener noreferrer"&gt;github.com/quod-lang/quod&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>dafny</category>
      <category>formalverification</category>
      <category>ai</category>
      <category>llm</category>
    </item>
    <item>
      <title>What I learned using a 7B local LLM as the front end of a programming language</title>
      <dc:creator>Malek AIT OUARET</dc:creator>
      <pubDate>Sun, 18 Oct 2026 12:50:01 +0000</pubDate>
      <link>https://dev.to/malek_aitouaret_f026758c/what-i-learned-using-a-7b-local-llm-as-the-front-end-of-a-programming-language-1pcf</link>
      <guid>https://dev.to/malek_aitouaret_f026758c/what-i-learned-using-a-7b-local-llm-as-the-front-end-of-a-programming-language-1pcf</guid>
      <description>&lt;p&gt;Pseudocode is how we teach algorithms, yet it has never been executable. You can write "repeat divisor from 2 to 50"&lt;br&gt;
on a whiteboard, but not run it. I wanted to change that without inventing yet another syntax, so I built&lt;br&gt;
&lt;strong&gt;Pseudo.NET&lt;/strong&gt;: you write pseudocode however you like, and a &lt;em&gt;local&lt;/em&gt; language model turns it into a program.&lt;/p&gt;

&lt;p&gt;This is not a launch post. It is what I learned about putting a small LLM at the front of a compiler. If you are&lt;br&gt;
tempted to try something similar, maybe some of this saves you a few evenings.&lt;/p&gt;
&lt;h2&gt;
  
  
  The idea in one picture
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;free-form pseudocode  -&amp;gt;  local LLM  -&amp;gt;  JSON AST  -&amp;gt;  validate / repair  -&amp;gt;  deterministic C# backend  -&amp;gt;  normal build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The model never writes the final program. Its job ends at a &lt;strong&gt;structured tree&lt;/strong&gt; (a JSON AST with a fixed set of node&lt;br&gt;
kinds). Everything after that is ordinary, testable code: a validator, a type inference pass, and a backend that emits C#.&lt;br&gt;
That split is the single most important design decision, and everything below follows from it.&lt;/p&gt;

&lt;p&gt;Here is a program, written with tabs only, no braces, no &lt;code&gt;end if&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;We want to find all the prime numbers up to 50.

primes = a new list

define whether counter is prime, which returns a boolean
    isPrime = true
    if counter is less than 2 then
        isPrime = false
    repeat divisor from 2 to 50
        if divisor is less than counter then
            remainder = counter modulo divisor
            if remainder is equal to 0 then
                isPrime = false
    return isPrime

repeat counter from 2 to 50
    candidate = whether counter is prime
    if candidate then
        add counter to primes

print the text "Prime numbers up to 50:"
for each number in primes
    print number
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The same program works written in French ("définir est-ce que compteur est premier…"), and in other languages the model&lt;br&gt;
understands. The tool does not decide what the syntax is; the user does.&lt;/p&gt;
&lt;h2&gt;
  
  
  What I used
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A small model, &lt;code&gt;qwen2.5-coder:7b&lt;/code&gt;, run locally through Ollama. No account, no API key, and nothing leaves the machine
(which matters if the users are students).&lt;/li&gt;
&lt;li&gt;Temperature 0. For identical input, the output is the same.&lt;/li&gt;
&lt;li&gt;F# for the compiler, C# as the target, and an MSBuild package so a &lt;code&gt;.pseudo&lt;/code&gt; file builds like any other source file.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Lesson 1: a small model drops bare booleans
&lt;/h2&gt;

&lt;p&gt;My first AST had flags like &lt;code&gt;"tapped": true&lt;/code&gt; for keyboard input ("is the left arrow &lt;em&gt;held&lt;/em&gt; or was it &lt;em&gt;just pressed&lt;/em&gt;?").&lt;br&gt;
The 7B model quietly omitted them. Not always, but often enough that games behaved randomly: a piece that should move&lt;br&gt;
continuously moved once.&lt;/p&gt;

&lt;p&gt;What worked was replacing flags by &lt;strong&gt;named values&lt;/strong&gt;: &lt;code&gt;"press": "held"&lt;/code&gt; or &lt;code&gt;"press": "just_pressed"&lt;/code&gt;, and for drawing&lt;br&gt;
&lt;code&gt;"style": "filled"&lt;/code&gt; or &lt;code&gt;"style": "outline"&lt;/code&gt;. A string with a name is much harder to forget than a missing &lt;code&gt;true&lt;/code&gt;. Field&lt;br&gt;
order mattered too: putting &lt;code&gt;style&lt;/code&gt; right after &lt;code&gt;kind&lt;/code&gt; made the model fill it in far more reliably.&lt;/p&gt;

&lt;p&gt;A simplified example of what the model now returns for "while the left key is held":&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"kind"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"KeyPressed"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"key"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"left"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"press"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"held"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Lesson 2: concrete examples beat abstract rules, but long prompts backfire
&lt;/h2&gt;

&lt;p&gt;Rules written in prose ("a negated condition is a unary NOT") were followed inconsistently. A couple of tiny concrete&lt;br&gt;
JSON examples in the prompt fixed the same problems more reliably.&lt;/p&gt;

&lt;p&gt;The catch: every addition makes the prompt longer, and a longer prompt made the model &lt;strong&gt;forget something else&lt;/strong&gt;. I added a&lt;br&gt;
section about drawing and, a day later, noticed negations had regressed ("if not X" quietly became "X != false" and a game&lt;br&gt;
showed a black screen). The only defence I found was a regression net: a script that regenerates a set of sample programs&lt;br&gt;
from scratch with the real model and checks the generated C# against expectations. Every prompt change goes through it.&lt;br&gt;
If you do this, build that net first, not after the third surprise.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lesson 3: decide what you are allowed to repair
&lt;/h2&gt;

&lt;p&gt;Models make mistakes in the &lt;em&gt;shape&lt;/em&gt; of their output (a field named &lt;code&gt;operator&lt;/code&gt; instead of &lt;code&gt;op&lt;/code&gt;, a kind called &lt;code&gt;Call&lt;/code&gt;&lt;br&gt;
instead of &lt;code&gt;FunctionCallStmt&lt;/code&gt;, an array where an object was expected). Repairing those is fine, and I do it in a small&lt;br&gt;
normalisation pass.&lt;/p&gt;

&lt;p&gt;What I refuse to do is repair the &lt;strong&gt;user's words&lt;/strong&gt;: no keyword tables for "if / si / wenn" and no rewriting of text to&lt;br&gt;
make the model's life easier. The moment I did that, I would have reintroduced a syntax, just a hidden one. So the rule is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;First choice: teach the model better, through the prompt.&lt;/li&gt;
&lt;li&gt;Second: repair the shape of its JSON output.&lt;/li&gt;
&lt;li&gt;Never: touch the wording of what the user wrote.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For what remains, there is a validator that checks the tree structurally. If it finds problems, the compiler sends them&lt;br&gt;
back to the model for correction, at most twice. If the answer is still invalid, you get a warning, and the invalid answer&lt;br&gt;
is never cached.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lesson 4: determinism comes from caching, not from the model
&lt;/h2&gt;

&lt;p&gt;Even at temperature 0, I do not want to depend on "the model happens to answer the same way tomorrow". Answers are cached&lt;br&gt;
under a hash of (model + prompt + pseudocode), so an unchanged program never calls the model again, rebuilds are instant,&lt;br&gt;
and the same input always gives the same C#. The six sample programs even ship their cached answer, so a first build works&lt;br&gt;
without Ollama installed.&lt;/p&gt;

&lt;p&gt;If you edit the generated C# by hand, the tool keeps your edit until the pseudocode changes, then regenerates and saves the&lt;br&gt;
old file as a backup. The model is an interactive front end; the build stays boring.&lt;/p&gt;

&lt;h2&gt;
  
  
  What does not work (yet)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A 7B model is good, not perfect. Very long or ambiguous programs sometimes need rewording.&lt;/li&gt;
&lt;li&gt;A model can be &lt;strong&gt;charitable&lt;/strong&gt;: if a student writes something slightly wrong, it may guess the intent instead of
flagging the mistake. For teaching this is a real question. I am thinking about showing the interpreted structure
back to the student so they can check it.&lt;/li&gt;
&lt;li&gt;Windows only for now, and the first generation of a new program takes seconds to minutes depending on your hardware.&lt;/li&gt;
&lt;li&gt;It is a teaching tool. I would not use it for production code, and I would not trust the model for anything with security
implications.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Is it a good idea?
&lt;/h2&gt;

&lt;p&gt;For education, I think it is worth trying: the barrier to running an idea drops, and the generated C# is a real program a&lt;br&gt;
student can open afterwards. For anything else, probably not, because a grammar is exactly the thing that makes a language&lt;br&gt;
precise and predictable. I am deliberately trading that away, and the validator, the cache and the deterministic backend&lt;br&gt;
are how I try to get some of it back.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Visual Studio extension: &lt;a href="https://marketplace.visualstudio.com/items?itemName=pseudonet-lang.pseudonet" rel="noopener noreferrer"&gt;https://marketplace.visualstudio.com/items?itemName=pseudonet-lang.pseudonet&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Without Visual Studio: &lt;code&gt;dotnet new install PseudoNet.Templates&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Source (F#, MIT): &lt;a href="https://github.com/pseudonet-lang/pseudonet" rel="noopener noreferrer"&gt;https://github.com/pseudonet-lang/pseudonet&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Site: &lt;a href="https://pseudonet-lang.github.io/" rel="noopener noreferrer"&gt;https://pseudonet-lang.github.io/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I would love to hear where it breaks, and whether you have tried a model as a &lt;em&gt;parser&lt;/em&gt; rather than a chatbot.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Disclosure: I used an AI assistant to help draft and edit this article and to build parts of the tool. The experiments and conclusions come from my own work on the project.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>dotnet</category>
      <category>llm</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
