<?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: Amit</title>
    <description>The latest articles on DEV Community by Amit (@iamamitkumarsahoo).</description>
    <link>https://dev.to/iamamitkumarsahoo</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%2F950027%2F193225a7-7f6f-492d-863a-7bc8d32183a0.jpg</url>
      <title>DEV Community: Amit</title>
      <link>https://dev.to/iamamitkumarsahoo</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/iamamitkumarsahoo"/>
    <language>en</language>
    <item>
      <title>Learning Dad's Garden: From 4 Minutes of Phone Video to a Printed Watering Sheet, Offline</title>
      <dc:creator>Amit</dc:creator>
      <pubDate>Sun, 11 Oct 2026 19:08:54 +0000</pubDate>
      <link>https://dev.to/iamamitkumarsahoo/learning-dads-garden-from-4-minutes-of-phone-video-to-a-printed-watering-sheet-offline-52ic</link>
      <guid>https://dev.to/iamamitkumarsahoo/learning-dads-garden-from-4-minutes-of-phone-video-to-a-printed-watering-sheet-offline-52ic</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-week1-2026-10-05"&gt;Hacktoberfest Open-Source AI Challenge Week 1: Touch Grass&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;My dad has looked after our pot plants for years. On Sunday morning he filmed them on his phone and explained each pot as he went.&lt;/p&gt;

&lt;p&gt;At the bush with tag 12, he said: "Give regular amount of water, the usual amount."&lt;/p&gt;

&lt;p&gt;He knows exactly how much that is. I didn't. So I built a tool that finds every line like that and asks him.&lt;/p&gt;

&lt;p&gt;It's called Learning Dad's Garden. It turns his walk-through into a printed checklist I can take outside. Each pot gets a row, with a tick box for each day it needs something. Gemma 4 does the reading, on my laptop. Before anything prints, Dad answers the questions a beginner would ask.&lt;/p&gt;

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

&lt;p&gt;I'm taking up Dad's hobby, and he knows what every pot needs. Some of his instructions are exact. Plant with tag 4 gets "200 to 250 ml of water daily". For the pot with tag 9 he said "one cup of water or one and a half cup of water to be accurate, the green cup we have", which is exact, as long as nobody moves the green cup. Others only make sense if you already know the garden: "the usual amount", "water it regularly", "this plantation". To him, those are complete instructions.&lt;/p&gt;

&lt;p&gt;Learning Dad's Garden turns a walk-through like that into something I can follow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Dad films each part of the garden and talks, the way he would explain it to me in person. &lt;/li&gt;
&lt;li&gt;"Learning Dad's Garden" turns his speech into text and splits it into instructions. Then it checks that every amount and time came from his words.&lt;/li&gt;
&lt;li&gt;A gap check lists everything I couldn't act on. Dad answers on a local web page that shows the video frame and plays his voice from that moment. &lt;/li&gt;
&lt;li&gt;The sheet prints. Each row has the tags, what to do, how much and when, a box for each day it's due, and Dad's exact words underneath.&lt;/li&gt;
&lt;li&gt;I take the sheet outside, water, and tick. Each evening Dad checks the pots and marks every row: done right, missed or done wrong. My dad is grading my homework again.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The screen time comes first but it stays small. The routine lives on paper. This week I walk from pot to pot with the sheet and a pencil, and the laptop stays shut.&lt;/p&gt;

&lt;p&gt;It works for anyone learning a garden from someone who knows it by feel. The command line calls them the owner and the helper. In our house, that's Papa and me.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmp4pztsbojjdjj5selrw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmp4pztsbojjdjj5selrw.png" alt="The top of the printed sheet: a Do NOT box, then tag 12's row with the amount " width="800" height="495"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The top of our sheet. Tag 12's "usual amount" is now half a glass of water, in Dad's typed words. What he said on Sunday sits under the row.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/pmRC0_B7b8o" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/AmitSahoo45/learning-dads-garden" rel="noopener noreferrer"&gt;GitHub URL&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The licence is MIT.&lt;/p&gt;

&lt;p&gt;It's built on &lt;a href="https://github.com/SYSTRAN/faster-whisper" rel="noopener noreferrer"&gt;faster-whisper&lt;/a&gt;, &lt;a href="https://ollama.com" rel="noopener noreferrer"&gt;Ollama&lt;/a&gt;, Gemma 4, &lt;a href="https://github.com/PyAV-Org/PyAV" rel="noopener noreferrer"&gt;PyAV&lt;/a&gt;, &lt;a href="https://python-pillow.org" rel="noopener noreferrer"&gt;Pillow&lt;/a&gt;, &lt;a href="https://jinja.palletsprojects.com" rel="noopener noreferrer"&gt;Jinja2&lt;/a&gt; and headless Chromium for the PDF.&lt;/p&gt;

&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;

&lt;p&gt;The model has one narrow job, and plain Python checks its work at every step. Pipeline :&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Step&lt;/th&gt;
&lt;th&gt;Done by&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Speech to text, with the time of every word&lt;/td&gt;
&lt;td&gt;faster-whisper &lt;code&gt;small.en&lt;/code&gt;, on the CPU&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Split into instructions&lt;/td&gt;
&lt;td&gt;Gemma 4 E4B through Ollama, held to a JSON schema&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Grounding check&lt;/td&gt;
&lt;td&gt;Python&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Days on the sheet&lt;/td&gt;
&lt;td&gt;Python rules&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gap check&lt;/td&gt;
&lt;td&gt;Gemma's flags, a phrase list, structure rules&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Review&lt;/td&gt;
&lt;td&gt;A local page: standard-library server, plain JavaScript&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Print&lt;/td&gt;
&lt;td&gt;Jinja template, then headless Chromium&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  What Gemma is allowed to do
&lt;/h3&gt;

&lt;p&gt;Gemma gets the transcript of one part of the garden and a short list of rules. The first rule sets the boundary:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You are not a gardening expert. Never add advice, amounts, times or conditions that the speaker did not say. &lt;br&gt;
(Well, neither am I, which is the whole reason this project exists.)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Ollama's structured output holds Gemma to a JSON schema. For each instruction, Gemma returns the exact quote, the tag numbers, the kind (do, don't, do only if, or a note), a short command, the amount, the timing and the condition. It also lists any words a helper couldn't act on. An example:&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;"quote"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"water this daily in the morning or in the evening anytime when you are free give regular amount of water, the usual amount"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"pots_said"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"pots"&lt;/span&gt;&lt;span class="p"&gt;:&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;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;"do"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"what"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Water"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"amount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"regular amount of water, the usual amount"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"when"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"daily in the morning or in the evening anytime when you are free"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"condition"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"vague"&lt;/span&gt;&lt;span class="p"&gt;:&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;span class="p"&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;"which_pot"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"phrase"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"this"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&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;"how_much"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"phrase"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"regular amount of water, the usual amount"&lt;/span&gt;&lt;span class="p"&gt;}&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;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;p&gt;Gemma flagged both gaps on its own. It couldn't tell which pot "this" was, or how much "the usual amount" is. Both became questions for Dad.&lt;/p&gt;

&lt;p&gt;I kept Gemma's thinking on, which is its default, with temperature 0 and an 8,192-token context. Gemma 4 E4B can take audio as input, but Whisper still does the listening. The tool needs two things Whisper gives for every word. The time lets the review page play the right clip. The confidence lets the sheet mark words Whisper wasn't sure of. I also give Whisper a list of words from Indian gardens, like tulsi, money plant, curry leaves, lota, etc. so it expects them.&lt;/p&gt;

&lt;h3&gt;
  
  
  Every value has to be in Dad's words
&lt;/h3&gt;

&lt;p&gt;A model that restructures text will sometimes try to help. So nothing Gemma returns goes straight onto the sheet. First, the code finds each quote in the transcript, word for word or close to it, with a similarity of at least 0.8. Then it checks every amount, time and condition. A value must be copied from the instruction's own words, or from elsewhere in the same video. Every number in it must appear there too. Anything else is deleted.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;ground_field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;quote&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;transcript&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Where a field value came from.

    &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;said&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;: copied from the instruction&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s own words.
    &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;inferred&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;: copied from elsewhere in the same note (for example &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;do the
    same for 26&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;); the owner is asked to confirm it.
    None: not found; the value must be dropped.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;is_extractive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;quote&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="nf"&gt;numbers_ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;quote&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;said&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;is_extractive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;transcript&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="nf"&gt;numbers_ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;transcript&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;inferred&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;"Inferred" covers lines like "do the same for 26". The value is real but comes from another sentence, so the tool asks Dad to confirm it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Days come from rules
&lt;/h3&gt;

&lt;p&gt;The model never decides days. Plain rules turn the timing words into days on the sheet. "Daily" means every day. "Every alternate day", "one day gap" and "every 2 days" all mean days 1, 3, 5 and 7 on a 7-day sheet. That makes 11 rows on odd days and 5 on even days. A striped box means nothing to do that day.&lt;/p&gt;

&lt;h3&gt;
  
  
  The questions
&lt;/h3&gt;

&lt;p&gt;The gap check rebuilds its questions from the instructions whenever anything changes, and it never stores a question as the truth. An answer changes the instruction. "It's fine as is" dismisses that one question. The questions come from five places:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Gemma's own flags, like the two above.&lt;/li&gt;
&lt;li&gt;A phrase list of things people say instead of numbers. Three of its lines:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;how_much&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;\b(?:as usual|the usual(?: amount| way| quantity)?|like (?:usual|always|i do|before)|the same amount)\b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;how_often&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;\b(?:regularly|sometimes|occasionally|now and then|from time to time|often|frequently&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
                &lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;|once in a while|on and off)\b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;when_to_act&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;\bdepend(?:s|ing)?(?: on| upon)?(?: how| what| whether| if| the)(?: \w+){0,4}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Structure rules: a watering row with no amount, two amounts joined by "or" (tag 9's "100 to 200 ml or 250 ml"), a command that is only a verb and an amount (tag 11's "Keep around 200 ml"), and a Do NOT line that also has a timing.&lt;/li&gt;
&lt;li&gt;Coverage: tags that no instruction names. &lt;/li&gt;
&lt;li&gt;Whisper: a word it heard with less than 5% confidence gets a question if it lands in a field on the sheet. In Dad's quotes it gets a "(?)", as in "amount brown (?) should be not more than 200 ml".&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every question carries its moment in the video. The page shows the frame and plays Dad's voice from the first word of the instruction to the last. He doesn't have to remember what "this" meant, because he sees what the camera saw. For pot with tag 12 he typed "This is tag number 12", then "that is usually 1/2 glass of water".&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjy29k013s0c0wh5okjzb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjy29k013s0c0wh5okjzb.png" alt="The questions page. It quotes Dad's words for tag 6 and asks what Amit should do, and how often. The answer box says " width="799" height="500"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The tag 6 question, on a copy of the project without our videos, so the frame and audio player are missing. The green line repeats the previous answer back.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;For the record, Plant (Tag #12) usual amount is half a glass of water. It took a 19-second video, a local AI model and one question to find that out. I could also have just asked him.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Does Open Innovation Matter?
&lt;/h2&gt;

&lt;p&gt;The videos show our front door, our pots and my dad's voice. With Gemma and Whisper running on my laptop, none of it leaves the house, and after the first model download a full run works with the Wi-Fi off. Each run costs nothing, so I could re-run it as often as I liked. Anyone taking over a garden can run it too. It needs Docker and, for speed, an NVIDIA GPU, with Gemma 4 E2B as the smaller fallback.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prize Categories
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Best Use of Gemma.&lt;/strong&gt; Gemma 4 E4B does all the reading. It splits Dad's speech into instructions, flags the words a beginner can't act on and, as an option, reads tag numbers in video frames. It runs locally through Ollama.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
      <category>ai</category>
      <category>opensource</category>
    </item>
    <item>
      <title>BreakMyQuery: find the row that breaks your SQL</title>
      <dc:creator>Amit</dc:creator>
      <pubDate>Sun, 04 Oct 2026 14:55:47 +0000</pubDate>
      <link>https://dev.to/iamamitkumarsahoo/breakmyquery-find-the-row-that-breaks-your-sql-31ak</link>
      <guid>https://dev.to/iamamitkumarsahoo/breakmyquery-find-the-row-that-breaks-your-sql-31ak</guid>
      <description>&lt;h1&gt;
  
  
  BreakMyQuery: find the row that breaks your SQL
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-weekend-2026-10-01"&gt;Hacktoberfest Weekend Challenge: Build for a Friend&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;I built BreakMyQuery for a colleague(also a friend🫠) who is a new graduate hire and is struggling with SQL joins or let's say he's scared of SQL joins.&lt;/p&gt;

&lt;p&gt;A query can pass the sample data while quietly dropping a customer who has no orders. For someone learning joins, seeing the missing customer gives them a concrete place to start investigating.&lt;/p&gt;

&lt;p&gt;BreakMyQuery offers eight SQLite exercises covering joins, NULLs, aggregation, ties, arithmetic, dates, and anti-joins. The learner writes a query, runs it, inspects any counterexample, and tries a repair. Each counterexample shows the breaking dataset, the learner's result, and the expected result. &lt;strong&gt;My traps&lt;/strong&gt; saves their mistakes so they can revisit a query through &lt;strong&gt;Retry&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I have demonstrated the app to my friend(or colleague). The goal is to help them connect the query they wrote to the rows it keeps, loses, or duplicates.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://breakmyquery.streamlit.app" rel="noopener noreferrer"&gt;Try BreakMyQuery&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The first exercise asks for every customer's name and their number of paid orders, including customers with zero paid orders.&lt;/p&gt;

&lt;p&gt;That one row exposes the problem. The learner can trace why Alice disappears and change their query. The app keeps the reference SQL out of the interface.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/AmitSahoo45/breakmyquery/blob/main/docs/hosted-verification.md" rel="noopener noreferrer"&gt;hosted verification record&lt;/a&gt; documents the tested counterexample, accepted-query, error, history, and Retry paths.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/AmitSahoo45/breakmyquery" rel="noopener noreferrer"&gt;Source code, exercises, tests, and setup instructions&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The application code uses the MIT license. The model weights have their own licenses.&lt;/p&gt;

&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;

&lt;p&gt;The stack is Python, Streamlit, SQLite, and Pydantic. The hosted demo uses the open-weight &lt;strong&gt;&lt;a href="https://ai.google.dev/gemma/docs/core/model_card_4" rel="noopener noreferrer"&gt;Gemma 4 26B A4B&lt;/a&gt;&lt;/strong&gt; model through Google's Gemini API.&lt;/p&gt;

&lt;p&gt;The app first checks the sample. If the results match, it searches for a breaking case:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Propose.&lt;/strong&gt; The model receives the schema, exercise question, learner query, and reference query. It proposes small datasets intended to make the queries disagree.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verify.&lt;/strong&gt; The app validates the proposed data and executes both queries in SQLite. It compares results while preserving duplicate-row counts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shrink.&lt;/strong&gt; It removes rows while preserving the mismatch and database constraints.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Practice.&lt;/strong&gt; The learner sees the remaining data and differing results, then edits their own query.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Seeded random fuzzing generates additional datasets and provides a fallback when the model returns no usable proposal or the API is unavailable. The hunter does not use the exercise's authored trap fixtures.&lt;/p&gt;

&lt;h3&gt;
  
  
  What the evaluations showed
&lt;/h3&gt;

&lt;p&gt;I evaluated model proposals and fuzzing separately against 14 deliberately wrong queries and eight equivalent alternatives.&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;Wrong queries exposed&lt;/th&gt;
&lt;th&gt;False positives on alternatives&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Gemma 4 via API&lt;/td&gt;
&lt;td&gt;14/14&lt;/td&gt;
&lt;td&gt;0/8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Using Local Llama 3.2&lt;/td&gt;
&lt;td&gt;9/14&lt;/td&gt;
&lt;td&gt;0/8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Seeded random fuzzing&lt;/td&gt;
&lt;td&gt;14/14&lt;/td&gt;
&lt;td&gt;0/8&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The Gemma catalog evaluation used live API calls from the local checkout; the deployed app was checked separately.&lt;/p&gt;

&lt;p&gt;Gemma's figures combine the primary run with one explicit follow-up after an unusable response. Covering the 22 cases took 23 model attempts. The &lt;a href="https://github.com/AmitSahoo45/breakmyquery/blob/main/eval_results_gemma_api.md" rel="noopener noreferrer"&gt;Gemma report&lt;/a&gt; preserves that failed call; the &lt;a href="https://github.com/AmitSahoo45/breakmyquery/blob/main/eval_results_llama32.md" rel="noopener noreferrer"&gt;Llama report&lt;/a&gt; records the separate local trial.&lt;/p&gt;

&lt;p&gt;On this catalog, random testing caught five mistakes Llama missed. Keeping both methods gives the app another chance to find a breaking case.&lt;/p&gt;

&lt;p&gt;I also found a teaching problem: Llama could produce a valid counterexample and still explain its cause incorrectly. I disabled generated hints and mistake labels in the demo. Gemma's teaching quality remains unevaluated. The tables and query results give the learner evidence they can inspect.&lt;/p&gt;

&lt;p&gt;These measurements cover a small authored catalog. &lt;strong&gt;A passing run means no counterexample was found within the search budget.&lt;/strong&gt; It does not prove the query correct.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Does Open Innovation Matter?
&lt;/h2&gt;

&lt;p&gt;Open weights give this project a local deployment option. Once the dependencies, runtime, and model are installed, the Ollama workflow runs inference and SQLite on the learner's computer without a hosted inference API.&lt;/p&gt;

&lt;p&gt;The public demo offers an easier starting point: my friend can open a link without installing a model. That convenience has a different data path. Submitted SQL goes to Google, and SQLite verification runs on the app server. The interface discloses this.&lt;/p&gt;

&lt;p&gt;I could evaluate local Llama and Gemma through the API using the same SQLite checker. Another developer can inspect that checker, swap the model, and repeat the evaluation. The model's role is explicit: it proposes cases, and SQLite checks whether they demonstrate a mistake.&lt;/p&gt;

&lt;p&gt;The counterexample approach was inspired by &lt;a href="https://www.cse.iitb.ac.in/infolab/XData/XData.html" rel="noopener noreferrer"&gt;XData at IIT Bombay&lt;/a&gt;. BreakMyQuery applies that idea to a small practice tool for my friend: find a concrete case, inspect the rows, and work out the repair.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prize Categories
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Best Use of Gemma:&lt;/strong&gt; Gemma 4 proposes the breaking datasets used by the hosted demo. SQLite verifies each accepted counterexample before the learner sees it.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>weekendchallenge</category>
      <category>hf26challenge</category>
    </item>
    <item>
      <title>How AI text watermarking works</title>
      <dc:creator>Amit</dc:creator>
      <pubDate>Sun, 27 Sep 2026 16:58:01 +0000</pubDate>
      <link>https://dev.to/iamamitkumarsahoo/how-ai-text-watermarking-works-4d03</link>
      <guid>https://dev.to/iamamitkumarsahoo/how-ai-text-watermarking-works-4d03</guid>
      <description>&lt;p&gt;An AI model can leave a watermark in the words it chooses. The text looks ordinary, and the mark can survive being copied into Notepad because it is carried by the token sequence. A detector with the matching key can check for that pattern later.&lt;/p&gt;

&lt;p&gt;Anthropic explained its approach in August 2026 in &lt;a href="https://www.anthropic.com/news/claude-text-watermark" rel="noopener noreferrer"&gt;"How Claude's text watermark works"&lt;/a&gt;. It uses a version of SynthID-Text, which Google DeepMind published in &lt;a href="https://www.nature.com/articles/s41586-024-08025-4" rel="noopener noreferrer"&gt;&lt;em&gt;Nature&lt;/em&gt; in 2024&lt;/a&gt;. Anthropic says it is introducing watermarking to meet the EU AI Act's transparency requirements.&lt;/p&gt;

&lt;p&gt;I wanted to understand how ordinary word choices could carry a signature, and what a detector finding that signature would actually tell us. I followed the choice of one token through the process, then tested a small implementation with GPT-2 in Google Colab.&lt;/p&gt;

&lt;h2&gt;
  
  
  Starting with one word
&lt;/h2&gt;

&lt;p&gt;Let's say you upload a photo of a cat to Claude and ask, "What is the cat in this image doing?" Claude starts its answer with "The cat" and now has to pick the next token.&lt;/p&gt;

&lt;p&gt;A language model writes one token at a time. A token can be a word, part of a word or punctuation. GPT-2's tokenizer for example, has roughly 50,000 tokens. The model assigns probabilities to possible next tokens. For a simplified example, assume only these three options have non-zero probabilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;sits&lt;/code&gt;: 50%&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sat&lt;/code&gt;: 30%&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;lies&lt;/code&gt;: 20%&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are invented probabilities and not actual measurements. We will treat each word as one token throughout the example. Without a watermark, sampling from these probabilities would pick "sits" about half of the time. The chosen token joins the sentence, and model calculates probabilities for the next token. The watermark changes how the next token is selected. Model's weights remain unchanged. For the same input, it still produces same initial probabilities. Watermarking just influences the selection.&lt;/p&gt;

&lt;p&gt;Without the watermark, a model might write "The cat sits on the mat." With the watermark, it might write "The cat sat on the rug" instead. These are just illustrative outcomes. The choices happen as the text is generated.&lt;/p&gt;

&lt;p&gt;A secret key, combined with the preceding tokens, determines the watermark scores for each possible next token. Changing the preceding tokens can change the scores. With same key, settings and token context, calculation gives the same scores every time. That repeatability makes detection possible later.&lt;/p&gt;

&lt;h2&gt;
  
  
  The tournament
&lt;/h2&gt;

&lt;p&gt;SynthID-Text uses a method called &lt;strong&gt;tournament sampling&lt;/strong&gt; to choose the next token. We can follow it through an example with four candidates and two rounds.&lt;br&gt;
Suppose a model has written "The cat" and assigns these probabilities to the next token:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Token&lt;/th&gt;
&lt;th&gt;Probability&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;sits&lt;/td&gt;
&lt;td&gt;50%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;sat&lt;/td&gt;
&lt;td&gt;30%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;lies&lt;/td&gt;
&lt;td&gt;20%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;First, we draw four candidates using those probabilities. Each draw can pick any of three tokens, including one already picked. One possible result is:&lt;br&gt;
&lt;code&gt;sits, sat, sits, lies&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;"sits" appears twice in this draw. It's 50% probability makes it more likely to appear, but &lt;strong&gt;that does not guarantee two places&lt;/strong&gt;. &lt;br&gt;
Next, watermarking algorithm uses key and preceding tokens to calculate a score of 0 or 1 for each candidate. Each round has its own scoring function. Within a round, repeated copies of the same token receive the same score. Suppose scores produce these matches:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Round&lt;/th&gt;
&lt;th&gt;Match&lt;/th&gt;
&lt;th&gt;Winner&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;sits (0) versus sat (1)&lt;/td&gt;
&lt;td&gt;sat&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;sits (0) versus lies (1)&lt;/td&gt;
&lt;td&gt;lies&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;sat (1) versus lies (0)&lt;/td&gt;
&lt;td&gt;sat&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The higher score wins each match. Ties are broken randomly. A token's score can differ between rounds, which is why "lies" scores 1 in the first round and 0 in the second. The winning token is "sat", so text now reads "The cat sat". Generation continues from there.&lt;/p&gt;

&lt;p&gt;Although "sits" had the highest original probability, both of its copies lost in this tournament. Another draw could produce a different winner. The model's probabilities determine how likely candidates are to enter, and watermark scores determine which candidates advance. This is method described in &lt;a href="https://www.nature.com/articles/s41586-024-08025-4" rel="noopener noreferrer"&gt;SynthID-Text paper&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Picking "sat" once provides little evidence of a watermark. An unwatermarked model could pick it too. Across many tokens watermarked text tends to have higher watermark scores than expected by chance. The detector measures that tendency. The bracket helps explain the method. The implementation discussed later calculates the equivalent winning probabilities directly.&lt;/p&gt;
&lt;h3&gt;
  
  
  Does watermarking affect writing quality??? 🤔
&lt;/h3&gt;

&lt;p&gt;Drawing candidates from the model's probabilities keeps likely continuations well represented. That alone does not guarantee good writing. SynthID-Text has a quality-preserving configuration and another that produces a stronger watermark at a cost to quality. Google tested the quality-preserving configuration on nearly 20 million Gemini responses. The paper reports no statistically significant difference in thumbs-up or thumbs-down ratings between watermarked and unwatermarked responses. When the model has very little choice about the next token, there is less room to leave a watermark. This makes detection harder in passages where accurate wording leaves few alternatives.&lt;/p&gt;
&lt;h2&gt;
  
  
  How a detector checks without the prompt
&lt;/h2&gt;

&lt;p&gt;The detector uses text, secret key and same watermark settings used during generation. It also needs the matching tokenizer to split the text into tokens. For each token, it takes the preceding tokens and calculates that token's watermark scores again. The calculation is repeatable: the same inputs produce the same scores.&lt;/p&gt;

&lt;p&gt;This works without the prompt because the preceding tokens are already in passage. With a four-token context, detector skips scoring the first four tokens. From the fifth token onward, it has the context it needs. A simple detector averages recovered scores across the eligible tokens. It skips repeated contexts so that a repeated phrase does not count as fresh evidence. SynthID-Text also supports more sophisticated detectors.&lt;/p&gt;

&lt;p&gt;For text written without this watermark, average is expected to be around 0.5 because the scoring functions assign roughly equal numbers of zeros and ones. Watermarked text tends to score higher because tournament favours tokens with higher scores. An average above 0.5 is not enough on its own to establish a watermark. Short passages can score high by chance. Longer passages usually provide more evidence, provided enough of the watermark survives.&lt;/p&gt;

&lt;p&gt;Detectors use thresholds calibrated against unwatermarked text to control false positives. For a simple average-based approach, the threshold also needs to account for text length. Editing can weaken the signal because it changes the inputs to the scoring functions. With a five-token window, replacing one token affects the score inputs for that position and the next four. Replacing a whole word may affect more tokens, depending on how it is tokenized. Small edits can leave much of the original signal intact. Extensive rewriting can make the watermark undetectable.&lt;/p&gt;
&lt;h2&gt;
  
  
  How the code implements the tournament
&lt;/h2&gt;

&lt;p&gt;A tournament with 30 rounds would require 2&lt;sup&gt;30&lt;/sup&gt; candidates for each token, which is over a billion. The implementation calculates the equivalent winning probabilities directly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;depth&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;g_values_at_depth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;g_values&lt;/span&gt;&lt;span class="p"&gt;[:,&lt;/span&gt; &lt;span class="p"&gt;:,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;g_mass_at_depth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;g_values_at_depth&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;probs&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;axis&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;keepdims&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;probs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;probs&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;g_values_at_depth&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;g_mass_at_depth&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;g_values&lt;/code&gt; contains the watermark scores, and &lt;code&gt;depth&lt;/code&gt; is the number of rounds. Each round adjusts the probabilities to favour tokens that scored 1. The adjustment depends on how much probability those tokens already hold. Using our cat example, the probabilities change as follows. In round 1, "sat" and "lies" score 1. In round 2, only "sat" scores 1; "sits" and "lies" both score 0.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Token&lt;/th&gt;
&lt;th&gt;Original probability&lt;/th&gt;
&lt;th&gt;After round 1&lt;/th&gt;
&lt;th&gt;After round 2&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;sits&lt;/td&gt;
&lt;td&gt;50%&lt;/td&gt;
&lt;td&gt;25%&lt;/td&gt;
&lt;td&gt;13.75%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;sat&lt;/td&gt;
&lt;td&gt;30%&lt;/td&gt;
&lt;td&gt;45%&lt;/td&gt;
&lt;td&gt;69.75%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;lies&lt;/td&gt;
&lt;td&gt;20%&lt;/td&gt;
&lt;td&gt;30%&lt;/td&gt;
&lt;td&gt;16.5%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The 69.75% comes from the chance that at least one finalist is "sat". After round 1, each finalist has a 45% chance of being "sat", so each has a 55% chance of being something else. The chance that neither is "sat" is &lt;code&gt;0.55 × 0.55 = 0.3025&lt;/code&gt;, or 30.25%. Since "sat" beats the other tokens in round 2, its chance of winning is &lt;code&gt;100% - 30.25% = 69.75%&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The implementation calculates these winning probabilities and makes one random choice from them. This gives each token the same chance of selection as running the tournament. "sat" is the most likely choice, but the other tokens still have a combined 30.25% chance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing with GPT-2
&lt;/h2&gt;

&lt;p&gt;I used GPT-2 in Google Colab to generate text with and without a watermark. The setup used 30 key values for 30 watermarking rounds, a five-token window, &lt;code&gt;top_k=40&lt;/code&gt; and &lt;code&gt;temperature=0.7&lt;/code&gt;. Each response could contain up to 300 new tokens.&lt;/p&gt;

&lt;p&gt;For each of five prompts, I generated one watermarked response and one plain response. I then took the first 20 words of the watermarked response. Separately, I made an edited version of the full watermarked response by replacing one word in four, starting with the first, with a random choice from "the", "a", "very" and "also". These replacements test the effect of disruptive edits rather than natural paraphrasing. I also scored an F1 text sample.&lt;/p&gt;

&lt;p&gt;The detector averaged the watermark scores after excluding the opening tokens, repeated contexts and end-of-text padding. It produced a raw average score, not a probability that the text was AI-generated.&lt;/p&gt;

&lt;p&gt;The first cell loads GPT-2 and sets the watermark configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;random&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;transformers&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AutoTokenizer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;AutoModelForCausalLM&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SynthIDTextWatermarkingConfig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SynthIDTextWatermarkLogitsProcessor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;DEVICE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cuda&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cuda&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;is_available&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cpu&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;tok&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AutoTokenizer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_pretrained&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gpt2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AutoModelForCausalLM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_pretrained&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gpt2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DEVICE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;CFG&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ngram_len&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;keys&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;654&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;836&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;123&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;340&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;443&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;597&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;160&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;57&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;29&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;590&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;639&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;715&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;468&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;990&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;966&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;226&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;324&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;585&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;118&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;504&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;421&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;521&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;129&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;669&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;732&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;225&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;90&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;960&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="n"&gt;sampling_table_size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sampling_table_seed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;context_history_size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;wm_config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SynthIDTextWatermarkingConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;CFG&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;lp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SynthIDTextWatermarkLogitsProcessor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;CFG&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;DEVICE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The second generates a response with or without the watermark:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;gen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;watermark&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;inp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;tok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;return_tensors&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DEVICE&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="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;inp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;do_sample&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;top_k&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;temperature&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;max_new_tokens&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pad_token_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;tok&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eos_token_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;watermarking_config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;wm_config&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;watermark&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;tok&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;inp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;input_ids&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shape&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]:],&lt;/span&gt; &lt;span class="n"&gt;skip_special_tokens&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The third calculates the average watermark score:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;score&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;ids&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;tok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;return_tensors&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;input_ids&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DEVICE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;g&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compute_g_values&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input_ids&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;ids&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;float&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  
    &lt;span class="n"&gt;eos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compute_eos_token_mask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input_ids&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;ids&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;eos_token_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;tok&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eos_token_id&lt;/span&gt;&lt;span class="p"&gt;)[:,&lt;/span&gt; &lt;span class="n"&gt;CFG&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ngram_len&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:]&lt;/span&gt;
    &lt;span class="n"&gt;rep&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compute_context_repetition_mask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input_ids&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;ids&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;eos&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;rep&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;float&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;unsqueeze&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;return &lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;sum&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;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shape&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])).&lt;/span&gt;&lt;span class="nf"&gt;item&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The fourth runs the comparisons:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;prompts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Write about how coffee is grown and exported.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Explain how trains work.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Descrieb a day at the beach.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Tell the history of the bicycle.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Explain how rain forms.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;human&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;George Russell won the Azerbaijan Grand Prix in Baku on Saturday, 26 September, converting pole position into his third victory of the season. It was not a quiet afternoon. The race had two safety car periods, six retirements, and a finish so close that Russell crossed the line only a tenth of a second ahead of Max Verstappen. Isack Hadjar completed the podium in third place.

The first safety car came out after Alex Albon made an error and binned his Williams. The second followed by Franco Colapinto torpedo&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ing himself in turn 1, which also ended the races of his teammate Pierre Gasly and Lando Norris. Both Aston Martins retired with mechanical problems. Oscar Piastri led for much of the race, but a lock-up cost him badly and he finished fourteenth. Charles Leclerc took fourth and Lewis Hamilton sixth. Kimi Antonelli had one of the best drives of the day, climbing from sixteenth to fifth.

The result extends Russell&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s championship lead and denies Verstappen his first win of the season.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;edit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;every&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;choice&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;the&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;a&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;very&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;also&lt;/span&gt;&lt;span class="sh"&gt;"&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;i&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;every&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;
                    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="n"&gt;rows&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;WM long&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Plain long&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;WM short (20 words)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;WM 25% edited&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[]}&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;prompts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;wm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;plain&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;gen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;gen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;WM long&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;score&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;wm&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Plain long&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;score&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;plain&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;WM short (20 words)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;score&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;wm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;()[:&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;])))&lt;/span&gt;
    &lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;WM 25% edited&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;score&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;edit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;wm&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;items&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;22&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; mean=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;  runs=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;round&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="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Human text (F1)&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;22&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;score&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;human&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Results
&lt;/h2&gt;

&lt;p&gt;These scores are from one run. Generation and word replacement are random, so reruns can produce different values.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Text&lt;/th&gt;
&lt;th&gt;Average score&lt;/th&gt;
&lt;th&gt;Range across five prompts&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Watermarked responses&lt;/td&gt;
&lt;td&gt;0.564&lt;/td&gt;
&lt;td&gt;0.548 to 0.586&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Plain GPT-2 responses&lt;/td&gt;
&lt;td&gt;0.497&lt;/td&gt;
&lt;td&gt;0.489 to 0.509&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;First 20 words of watermarked responses&lt;/td&gt;
&lt;td&gt;0.573&lt;/td&gt;
&lt;td&gt;0.545 to 0.607&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Watermarked responses with every fourth word edited&lt;/td&gt;
&lt;td&gt;0.500&lt;/td&gt;
&lt;td&gt;0.495 to 0.504&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;F1 text sample&lt;/td&gt;
&lt;td&gt;0.498&lt;/td&gt;
&lt;td&gt;One sample&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The watermarked and plain responses had no overlapping scores in these five runs. The F1 sample scored close to the plain responses. This shows a clear difference in this experiment, though more samples would be needed to establish a reliable detection threshold and measure false positives.&lt;/p&gt;

&lt;p&gt;The short excerpts also scored high, but I did not test short unwatermarked excerpts for comparison. These results cannot establish reliable detection on short passages.&lt;/p&gt;

&lt;p&gt;Replacing every fourth word brought the average down to 0.500, close to the unwatermarked baseline. This editing pattern weakened the signal measured by this detector. It does not establish that changing any 25% of a passage would have the same effect.&lt;/p&gt;

&lt;p&gt;This experiment used GPT-2 and the configuration shown above. It does not measure the performance of Claude's watermark. A detected watermark provides evidence that the matching watermarking system was involved in producing the text. Failing to detect one does not establish that a person wrote it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.anthropic.com/news/claude-text-watermark" rel="noopener noreferrer"&gt;Anthropic, "How Claude's text watermark works" (August 2026)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://support.claude.com/en/articles/16266773-how-claude-marks-ai-generated-content" rel="noopener noreferrer"&gt;Claude Help Center, "How Claude marks AI-generated content"&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://doi.org/10.1038/s41586-024-08025-4" rel="noopener noreferrer"&gt;Dathathri et al., "Scalable watermarking for identifying large language model outputs," Nature 634, pages 818-823 (2024)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/google-deepmind/synthid-text" rel="noopener noreferrer"&gt;Google DeepMind, SynthID-Text repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/huggingface/transformers/blob/main/src/transformers/generation/logits_process.py" rel="noopener noreferrer"&gt;Hugging Face Transformers, SynthIDTextWatermarkLogitsProcessor source&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
    </item>
    <item>
      <title>Our SQL Server loop kept writing the previous row's value</title>
      <dc:creator>Amit</dc:creator>
      <pubDate>Sun, 28 Jun 2026 16:08:34 +0000</pubDate>
      <link>https://dev.to/iamamitkumarsahoo/our-sql-server-loop-kept-writing-the-previous-rows-value-1gn4</link>
      <guid>https://dev.to/iamamitkumarsahoo/our-sql-server-loop-kept-writing-the-previous-rows-value-1gn4</guid>
      <description>&lt;p&gt;&lt;em&gt;A loop that looks correct, passes review, and still writes the wrong value, because of two documented T-SQL behaviors.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Here's a loop that resolves a value for each item: read it from a primary table, fall back to a secondary one when the primary has nothing, write the result. It looks correct. On the wrong data it writes the wrong value, and the wrong value isn't random: each bad row gets the value belonging to the row processed just before it.&lt;/p&gt;

&lt;p&gt;No error, no exception. The loop reads correctly top to bottom. The cause is two T-SQL behaviors that Microsoft documents and that are easy to misread:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A variable declared inside a loop is set to &lt;code&gt;NULL&lt;/code&gt; once for the whole batch, not once per iteration.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;SELECT @var = column&lt;/code&gt; leaves the variable alone when the query returns no rows.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Either one is survivable alone. Together they make a missing row reuse the last good answer.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the code looks like
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;WHILE&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;cnt&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;BEGIN&lt;/span&gt;
    &lt;span class="k"&gt;DECLARE&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;Item_Code&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ITEM&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;ItemList&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;RowNo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;cnt&lt;/span&gt;

    &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;isnull&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ITEM_VAL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ITEM_VAL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="k"&gt;Primary&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;
    &lt;span class="k"&gt;LEFT&lt;/span&gt; &lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;Fallback&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ITEM_CODE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ITEM_CODE&lt;/span&gt;
    &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ITEM_CODE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;Item_Code&lt;/span&gt;
      &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ITEM_SEQ&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;MAX&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pmax&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ITEM_SEQ&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="k"&gt;Primary&lt;/span&gt; &lt;span class="n"&gt;pmax&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;pmax&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ITEM_CODE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;Item_Code&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt; &lt;span class="k"&gt;IS&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;OR&lt;/span&gt; &lt;span class="n"&gt;LTRIM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;RTRIM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;
    &lt;span class="k"&gt;BEGIN&lt;/span&gt;
        &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;TOP&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ITEM_VAL&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;Fallback&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;ITEM_CODE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;Item_Code&lt;/span&gt;
    &lt;span class="k"&gt;END&lt;/span&gt;

    &lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;Target&lt;/span&gt; &lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;ITEM_VAL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;ITEM_CODE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;Item_Code&lt;/span&gt;
    &lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;cnt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;cnt&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="k"&gt;END&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Read top to bottom, the intent is plain: resolve from the primary table, fall back to the secondary one, write the result. The &lt;code&gt;DECLARE @Value&lt;/code&gt; inside the loop looks like it hands each pass a clean variable. That assumption is the trap.&lt;/p&gt;

&lt;h2&gt;
  
  
  A DECLARE inside a loop isn't a reset
&lt;/h2&gt;

&lt;p&gt;In C++, Java, or C#, a variable declared inside a loop body is a fresh binding every pass. T-SQL doesn't do that. A local variable's scope is the whole batch, and it's initialized to &lt;code&gt;NULL&lt;/code&gt; when it's declared, not at the point in the code where you wrote &lt;code&gt;DECLARE&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So putting &lt;code&gt;DECLARE @Value&lt;/code&gt; inside the &lt;code&gt;WHILE&lt;/code&gt; is just decoration. There's one &lt;code&gt;@Value&lt;/code&gt; for the whole run, set to &lt;code&gt;NULL&lt;/code&gt; once, and every iteration after the first inherits whatever the previous one left in it. That's also why SQL Server doesn't complain about a double declaration even though the &lt;code&gt;DECLARE&lt;/code&gt; line is reached on every pass; it isn't a statement that re-runs each time.&lt;/p&gt;

&lt;p&gt;A quick proof:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;DECLARE&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="n"&gt;WHILE&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
&lt;span class="k"&gt;BEGIN&lt;/span&gt;
    &lt;span class="k"&gt;DECLARE&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt;
    &lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;ISNULL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="n"&gt;PRINT&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;
    &lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="k"&gt;END&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It prints &lt;code&gt;1&lt;/code&gt;, &lt;code&gt;2&lt;/code&gt;, &lt;code&gt;3&lt;/code&gt;. If the &lt;code&gt;DECLARE&lt;/code&gt; reset &lt;code&gt;@x&lt;/code&gt; each pass, you'd get &lt;code&gt;1&lt;/code&gt;, &lt;code&gt;1&lt;/code&gt;, &lt;code&gt;1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Docs: &lt;a href="https://learn.microsoft.com/en-us/sql/t-sql/language-elements/declare-local-variable-transact-sql" rel="noopener noreferrer"&gt;DECLARE @local_variable (Transact-SQL)&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  SELECT-assignment does nothing when nothing matches
&lt;/h2&gt;

&lt;p&gt;The resolve uses &lt;code&gt;SELECT @Value = ...&lt;/code&gt;. When the item isn't in the primary table, the &lt;code&gt;WHERE&lt;/code&gt; returns no rows. You'd assume that sets &lt;code&gt;@Value&lt;/code&gt; to &lt;code&gt;NULL&lt;/code&gt;. It doesn't. With &lt;code&gt;SELECT&lt;/code&gt;-style assignment, a zero-row result leaves the variable exactly where it was.&lt;/p&gt;

&lt;p&gt;So on a missing item the assignment runs, changes nothing, and &lt;code&gt;@Value&lt;/code&gt; still holds whatever the previous item resolved to.&lt;/p&gt;

&lt;p&gt;Microsoft documents this exact case in Example A on that page: a variable set to a default, a &lt;code&gt;SELECT @var = ... WHERE&lt;/code&gt; that matches nothing, and the variable keeps the default.&lt;/p&gt;

&lt;p&gt;Docs: &lt;a href="https://learn.microsoft.com/en-us/sql/t-sql/language-elements/select-local-variable-transact-sql" rel="noopener noreferrer"&gt;SELECT @local_variable (Transact-SQL)&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  How the two combine
&lt;/h2&gt;

&lt;p&gt;Now the failure is just mechanics:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;@Value&lt;/code&gt; is never cleared between iterations.&lt;/li&gt;
&lt;li&gt;For an item missing from the primary table, the resolve matches nothing and doesn't touch &lt;code&gt;@Value&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The guard &lt;code&gt;IF (@Value IS NULL) OR LTRIM(RTRIM(@Value)) = ''&lt;/code&gt; sees a leftover non-null value, decides resolution already worked, and skips the fallback.&lt;/li&gt;
&lt;li&gt;The item gets written with the previous item's value.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The fallback that should have rescued the missing item never fires, because the stale value makes it look like there was nothing to rescue.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fixing it
&lt;/h2&gt;

&lt;p&gt;Two changes close the gap.&lt;/p&gt;

&lt;p&gt;Clear the variable at the top of every iteration so a missing row can't carry the last value forward:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;WHILE&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;cnt&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;BEGIN&lt;/span&gt;
    &lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="k"&gt;END&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And for a single-value lookup like this, prefer &lt;code&gt;SET&lt;/code&gt; with a scalar subquery over &lt;code&gt;SELECT&lt;/code&gt;-assignment. A scalar subquery that finds no rows gives you &lt;code&gt;NULL&lt;/code&gt;, which is what you want here, because then the &lt;code&gt;IS NULL&lt;/code&gt; guard does its job:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;isnull&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ITEM_VAL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ITEM_VAL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="k"&gt;Primary&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;
    &lt;span class="k"&gt;LEFT&lt;/span&gt; &lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;Fallback&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ITEM_CODE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ITEM_CODE&lt;/span&gt;
    &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ITEM_CODE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;Item_Code&lt;/span&gt;
      &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ITEM_SEQ&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;MAX&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pmax&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ITEM_SEQ&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="k"&gt;Primary&lt;/span&gt; &lt;span class="n"&gt;pmax&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;pmax&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ITEM_CODE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;Item_Code&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;It reads fine. Each behavior is harmless on its own, which is why the pair survives review. If a loop variable can outlive its iteration, assume it does.&lt;/p&gt;

</description>
      <category>sql</category>
      <category>sqlserver</category>
      <category>database</category>
    </item>
  </channel>
</rss>
