<?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: Hugo Valer</title>
    <description>The latest articles on DEV Community by Hugo Valer (@hugo_valer_79d0d94e00804b).</description>
    <link>https://dev.to/hugo_valer_79d0d94e00804b</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%2F2416269%2Fb24de9e5-7017-4e3c-bec3-1a1330309a29.jpg</url>
      <title>DEV Community: Hugo Valer</title>
      <link>https://dev.to/hugo_valer_79d0d94e00804b</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/hugo_valer_79d0d94e00804b"/>
    <language>en</language>
    <item>
      <title>Some models state the right DST rule, then apply last week's offset anyway. I tested 46 models; in the pre-registered part, 91% of wrong deadline conversions were exactly that one-hour mistake. It replicated, and the newest models fixed it.</title>
      <dc:creator>Hugo Valer</dc:creator>
      <pubDate>Wed, 07 Oct 2026 10:29:16 +0000</pubDate>
      <link>https://dev.to/hugo_valer_79d0d94e00804b/some-models-state-the-right-dst-rule-then-apply-last-weeks-offset-anyway-i-tested-46-models-in-4ie9</link>
      <guid>https://dev.to/hugo_valer_79d0d94e00804b/some-models-state-the-right-dst-rule-then-apply-last-weeks-offset-anyway-i-tested-46-models-in-4ie9</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/hugo_valer_79d0d94e00804b/the-model-knew-the-rule-it-still-used-last-weeks-offset-584m" class="crayons-story__hidden-navigation-link"&gt;The model knew the rule. It still used last week's offset.&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
      &lt;a href="https://dev.to/hugo_valer_79d0d94e00804b/the-model-knew-the-rule-it-still-used-last-weeks-offset-584m" class="crayons-article__context-note crayons-article__context-note__feed"&gt;&lt;p&gt;Kaggle Benchmarking Challenge Submission&lt;/p&gt;

&lt;/a&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/hugo_valer_79d0d94e00804b" class="crayons-avatar  crayons-avatar--l  "&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%2Fuser%2Fprofile_image%2F2416269%2Fb24de9e5-7017-4e3c-bec3-1a1330309a29.jpg" alt="hugo_valer_79d0d94e00804b profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/hugo_valer_79d0d94e00804b" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Hugo Valer
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Hugo Valer
                
                
              
              &lt;div id="story-author-preview-content-4810794" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/hugo_valer_79d0d94e00804b" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&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%2Fuser%2Fprofile_image%2F2416269%2Fb24de9e5-7017-4e3c-bec3-1a1330309a29.jpg" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Hugo Valer&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/hugo_valer_79d0d94e00804b/the-model-knew-the-rule-it-still-used-last-weeks-offset-584m" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Oct 7&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/hugo_valer_79d0d94e00804b/the-model-knew-the-rule-it-still-used-last-weeks-offset-584m" id="article-link-4810794"&gt;
          The model knew the rule. It still used last week's offset.
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/devchallenge"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;devchallenge&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/kagglechallenge"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;kagglechallenge&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/machinelearning"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;machinelearning&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/ai"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;ai&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/hugo_valer_79d0d94e00804b/the-model-knew-the-rule-it-still-used-last-weeks-offset-584m" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/exploding-head-daceb38d627e6ae9b730f36a1e390fca556a4289d5a41abb2c35068ad3e2c4b5.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;3&lt;span class="hidden s:inline"&gt;&amp;nbsp;reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/hugo_valer_79d0d94e00804b/the-model-knew-the-rule-it-still-used-last-weeks-offset-584m#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              5&lt;span class="hidden s:inline"&gt;&amp;nbsp;comments&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            13 min read
          &lt;/small&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
      <category>ai</category>
      <category>llm</category>
      <category>testing</category>
    </item>
    <item>
      <title>The model knew the rule. It still used last week's offset.</title>
      <dc:creator>Hugo Valer</dc:creator>
      <pubDate>Wed, 07 Oct 2026 08:15:36 +0000</pubDate>
      <link>https://dev.to/hugo_valer_79d0d94e00804b/the-model-knew-the-rule-it-still-used-last-weeks-offset-584m</link>
      <guid>https://dev.to/hugo_valer_79d0d94e00804b/the-model-knew-the-rule-it-still-used-last-weeks-offset-584m</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/kaggle-2026-09-23"&gt;Kaggle Benchmarking Challenge&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;A Kaggle benchmark about the most boring bug I know: converting a deadline into your own time zone. In the opening example, the two dates are one week apart; the measured result comes from 50 pre-registered trap/control pairs (controls moved 7 or 21 days out of the clock-change gap, plus durations that do or do not cross a clock change).&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This contest closes on &lt;strong&gt;October 11, 2026, at 11:59 PM PDT&lt;/strong&gt;. I live in Madrid, so for me it closes on &lt;strong&gt;Monday, October 12, at 08:59&lt;/strong&gt;. That is the kind of conversion I no longer trust myself to do by hand, so I asked 46 models to do it for me, plus 130 variations of it.&lt;/p&gt;

&lt;p&gt;The headline is not that models get time zones wrong. It is &lt;em&gt;how&lt;/em&gt; they get them wrong: in a pre-registered test, of the 321 wrong answers on trap dates that contained a time, &lt;strong&gt;293 (91%) were exactly the answer you get by applying the usual offset&lt;/strong&gt; (or by adding clock hours across a clock change). Some models even state the correct rule in their reasoning and then ignore it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In short:&lt;/strong&gt; across &lt;strong&gt;50 trap/control pairs&lt;/strong&gt;, the trap version of a sentence (a date inside the weeks when Europe and the US change clocks on different dates, or a duration that crosses a clock change) costs the 19 pre-registered models &lt;strong&gt;29.8 points&lt;/strong&gt; of accuracy on average compared with its control (95% CI +25.4 to +34.2); 13 of them get worse and none get better. The engineering recommendation that follows: let the model extract the date, time, and zone, and let a time-zone library do the arithmetic. (I did not compare prompting strategies, so I cannot say whether a better prompt would close the gap.)&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Task:&lt;/strong&gt; given a deadline as a contest page writes it ("Submissions close October 28, 2026 at 11:59 PM PT") and where the reader lives ("Madrid, Spain"), return the deadline in the reader's local time as &lt;code&gt;ANSWER: YYYY-MM-DD HH:MM&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Why this itch: I build tooling for hackathons, and the first rule I wrote for it was &lt;em&gt;never compute deadline hours by hand; store the canonical UTC instant and its source&lt;/em&gt;. This benchmark checks whether that rule is still needed when the one doing the arithmetic is an LLM.&lt;/p&gt;

&lt;p&gt;The trap that makes it interesting: in 2026, Europe leaves summer time on &lt;strong&gt;October 25&lt;/strong&gt; and the US on &lt;strong&gt;November 1&lt;/strong&gt;. For one week the usual Madrid–Los Angeles difference is 8 hours, not 9. The same happens in spring (US on March 8, Europe on March 29). Anything that "knows" the usual difference is wrong during those weeks, and so is anything that adds clock hours across a change.&lt;/p&gt;

&lt;p&gt;The benchmark has three case sets, all with &lt;strong&gt;exact ground truth&lt;/strong&gt;: every answer is computed with Python's &lt;code&gt;zoneinfo&lt;/code&gt; and checked against a hand-written answer when the file is imported (the confirmatory set is checked against a second, independent oracle written from the US and EU rules). No LLM judge anywhere.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Set&lt;/th&gt;
&lt;th&gt;Cases&lt;/th&gt;
&lt;th&gt;What it covers&lt;/th&gt;
&lt;th&gt;Status&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Standard&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;td&gt;day rollover, the autumn and spring gap weeks, &lt;code&gt;12 AM&lt;/code&gt; and AoE wording, non-hour offsets&lt;/td&gt;
&lt;td&gt;designed first&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hard&lt;/td&gt;
&lt;td&gt;11&lt;/td&gt;
&lt;td&gt;relative dates, durations across a clock change, a Unix timestamp, an ISO &lt;code&gt;Z&lt;/code&gt; time, described dates, a traveling reader&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;exploratory&lt;/strong&gt;: written after seeing the standard results&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pairs&lt;/td&gt;
&lt;td&gt;100 (50 pairs)&lt;/td&gt;
&lt;td&gt;each trap has a control twin with the same text, reader, clock time and weekday, moved out of the gap&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;pre-registered&lt;/strong&gt; before any run (&lt;a href="https://github.com/hvaler/deadline-math/blob/main/docs/PREREGISTRATION.md" rel="noopener noreferrer"&gt;pre-registration&lt;/a&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The standard and hard sets each run in two modes: &lt;strong&gt;direct&lt;/strong&gt; (reply with one line only, like a quick lookup or an agent writing to a calendar) and &lt;strong&gt;reasoned&lt;/strong&gt; (think briefly, then the answer line). The pre-registered pairs set runs in &lt;strong&gt;direct&lt;/strong&gt; mode only.&lt;/p&gt;

&lt;p&gt;One embarrassing detail belongs here. While building the hard set, &lt;em&gt;my own oracle&lt;/em&gt; got two cases wrong: in Python, &lt;code&gt;aware_datetime + timedelta(hours=48)&lt;/code&gt; with a &lt;code&gt;ZoneInfo&lt;/code&gt; zone adds &lt;strong&gt;wall-clock&lt;/strong&gt; hours and ignores the clock change. The cross-check between the hand-written answer and the computed one caught it. Keep that in mind for the findings: it is exactly the mistake the models make.&lt;/p&gt;

&lt;h2&gt;
  
  
  Models Tested
&lt;/h2&gt;

&lt;p&gt;Why these models: I did not pick favorites. I ran &lt;strong&gt;every model Kaggle Community Benchmarks offered&lt;/strong&gt;: 41 on October 3, 2026, plus the 5 it added by October 6 (Claude Opus 5.5 and Sonnet 5.5, GPT-6 Luna, GPT-6 Sol and GPT-6.1 Sol), from Anthropic, Google, OpenAI, xAI, Qwen, DeepSeek and Zhipu, because the question is practical: if you drop one of these into an agent that books your deadlines, which ones can you trust? That range also matters for the finding: it spans small and flagship models from the same families, so "it is just the small ones" can be tested rather than assumed. Not all of them could be measured:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;43 models&lt;/strong&gt; completed the four original tasks cleanly; they form the comparison cohort.&lt;/li&gt;
&lt;li&gt;3 could not be included because of &lt;strong&gt;infrastructure&lt;/strong&gt;, never because of their answers: Grok 4.5 and 4.6 returned "model not found" (404), and gpt-oss-120b was overloaded (429) so often that its last task finished only after the data freeze. They are &lt;em&gt;not completed&lt;/em&gt;, not 0%; gpt-oss-120b's late runs are visible on the leaderboard.&lt;/li&gt;
&lt;li&gt;The public Kaggle leaderboard only shows each task's latest run, and it shows a run that failed on infrastructure as a 0. So its pairs column shows the replication run (finding 4), and Qwen3 Next Thinking, which completed every task only on earlier runs before its latest ones failed with 429 errors, is in the GitHub data but not on the leaderboard.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every completed model ran each task at least once at temperature 0, and most ran it twice (see finding 6).&lt;/p&gt;

&lt;h2&gt;
  
  
  Findings
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. In the plain cases, the top of the field is saturated
&lt;/h3&gt;

&lt;p&gt;On the standard set in direct mode, 20 of 43 models score 20/20 (among them the Gemini 3.x Flash and Pro models, both Gemma 4 models, Claude Sonnet 5 and 5.5, Claude Opus 5.5, GPT-5.5, GPT-5.6 Sol, GPT-6 Sol, GPT-6.1 Sol, and GLM-5). A benchmark where everyone scores 100% tells you nothing, so the interesting signal lives in the middle of the field and in the harder sets.&lt;/p&gt;

&lt;p&gt;Cohort of 43 models with all four tasks:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Condition&lt;/th&gt;
&lt;th&gt;Correct&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Standard, direct&lt;/td&gt;
&lt;td&gt;726/860 (84.4%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Standard, reasoned&lt;/td&gt;
&lt;td&gt;812/860 (94.4%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hard, direct&lt;/td&gt;
&lt;td&gt;339/473 (71.7%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hard, reasoned&lt;/td&gt;
&lt;td&gt;380/473 (80.3%)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  2. Letting a model think helps the middle of the field, not the top
&lt;/h3&gt;

&lt;p&gt;Allowing a short reasoning step changes little for the strongest models, but a lot for mid-sized ones: on the standard set Claude Haiku 4.5 goes from 9/20 to 17/20, GPT-5.4 nano from 3/20 to 17/20, Qwen3 Next Instruct from 7/20 to 16/20, Qwen3 Coder 480B from 3/20 to 13/20. Given how much a single run varies (finding 6), read it as "the direct mode is where cheap models break", not as a precise effect size or a causal claim about reasoning.&lt;/p&gt;

&lt;p&gt;That matters because the direct mode approximates a common automation pattern: an agent producing a calendar-ready time, with nobody reading its reasoning.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. The failures are mechanical: exactly one hour
&lt;/h3&gt;

&lt;p&gt;Across the four tasks and the 43-model cohort, 409 answers missed the ground truth. Of the 382 misses with an extractable but incorrect time, &lt;strong&gt;235 (62%) were off by exactly one hour&lt;/strong&gt;. The pattern is strongest where the usual offset breaks: 51 of 52 such errors in the autumn gap week, 18 of 20 in the spring gap, and 56 of 71 on durations that cross a clock change.&lt;/p&gt;

&lt;p&gt;The models are not guessing. They apply the &lt;em&gt;usual&lt;/em&gt; offset:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Madrid is on Central European Time in late October, while PT on October 28, 2026 is Pacific Daylight Time (UTC−7). 11:59 PM PT on October 28, 2026 corresponds to 8:59 AM in Madrid on October 29, 2026." &lt;/p&gt;

&lt;p&gt;— GPT-5.4 mini (correct answer: 07:59)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It names the right rule (CET, not CEST) and then uses the 9-hour difference anyway.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Since it lasts exactly 48 hours, which is two full days, it will end at the same time two days later." &lt;/p&gt;

&lt;p&gt;— Gemini 2.5 Flash, on a hackathon starting Saturday Oct 24 at 18:00 in Madrid (correct answer: Monday 17:00)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is my &lt;code&gt;zoneinfo&lt;/code&gt; bug, written in English.&lt;/p&gt;

&lt;p&gt;And on this very contest's deadline:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"On October 11, 2026, Madrid will be on CET (UTC+1) since it will be after the end of daylight saving time in Europe (which ends on the last Sunday of October, October 25, 2026)." &lt;/p&gt;

&lt;p&gt;— Qwen3 Coder 480B (correct answer: 08:59; it answered 07:59)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It recites the right date for the change and then decides that October 11 comes after October 25.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. The confirmatory test: the same sentence, trap date vs. control date
&lt;/h3&gt;

&lt;p&gt;The claim above came from cases I designed after seeing failures. That is how you fool yourself, so before generating anything new, I wrote down the two hypotheses, the design, and the pass/fail criteria (&lt;a href="https://github.com/hvaler/deadline-math/blob/main/docs/PREREGISTRATION.md" rel="noopener noreferrer"&gt;pre-registration&lt;/a&gt;; the task notebook with all 100 cases was public on Kaggle before the first run). After writing the pre-registration, I ran a local pilot on two cheap models to check that the cases and the parser worked (it is not part of the analysis), then one run per pre-registered model on Kaggle; one model that failed on infrastructure was retried until it completed. The hypotheses:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;H1:&lt;/strong&gt; for the same sentence, accuracy drops when the date falls in a gap week (or a duration crosses a clock change) compared with its control twin. &lt;em&gt;Holds if the bootstrap 95% CI of the mean penalty is above zero.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;H2:&lt;/strong&gt; more than half of the wrong answers on traps equal the &lt;em&gt;naive&lt;/em&gt; answer: the usual offset, or clock-hour addition. &lt;em&gt;Holds if the lower bound of the Wilson 95% CI is above 50%.&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The set has 50 pairs. Each trap has a control twin with the same wording, reader, clock time, and weekday; only the date moves out of the gap. For example:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Statement&lt;/th&gt;
&lt;th&gt;Reader&lt;/th&gt;
&lt;th&gt;Correct&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Trap&lt;/td&gt;
&lt;td&gt;Submissions close Monday, October 26, 2026 at 11:59 PM PT.&lt;/td&gt;
&lt;td&gt;Madrid&lt;/td&gt;
&lt;td&gt;Oct 27, &lt;strong&gt;07:59&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Control&lt;/td&gt;
&lt;td&gt;Submissions close Monday, October 19, 2026 at 11:59 PM PT.&lt;/td&gt;
&lt;td&gt;Madrid&lt;/td&gt;
&lt;td&gt;Oct 20, &lt;strong&gt;08:59&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Every answer is computed with &lt;code&gt;zoneinfo&lt;/code&gt; and checked against a second oracle written by hand from the US and EU rules; the run would not start if they disagreed on a single case.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Result, pre-registered cohort (all 19 models completed):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;H1 holds.&lt;/strong&gt; Mean penalty: &lt;strong&gt;+29.8 percentage points&lt;/strong&gt; (95% bootstrap CI: +25.4 to +34.2). 13 models do worse on traps, none do better, and 6 show no difference (sign test p = 0.0002). The bootstrap resamples the 50 paired cases while keeping the 19-model cohort fixed, so the interval does not include the uncertainty of choosing other models or rerunning them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;H2 holds.&lt;/strong&gt; &lt;strong&gt;293 of 321&lt;/strong&gt; wrong trap answers with an extractable time (&lt;strong&gt;91%&lt;/strong&gt;, Wilson CI 88–94%) are &lt;em&gt;exactly&lt;/em&gt; the naive answer. Answers without an &lt;code&gt;ANSWER&lt;/code&gt; line are not in this count; they do count as failures in H1.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;It replicated.&lt;/strong&gt; Because temperature 0 is not deterministic (finding 6), I ran the same set once more on the same models, logged in advance as a secondary analysis. 18 of the 19 completed (Qwen3 Next Thinking failed every retry with 429 errors): mean penalty &lt;strong&gt;+29.6 points&lt;/strong&gt; (CI +26.0 to +33.1), and &lt;strong&gt;277 of 306&lt;/strong&gt; extractable trap errors (91%) were again exactly the naive answer.&lt;/p&gt;

&lt;p&gt;First run, all 19 pre-registered models:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Traps&lt;/th&gt;
&lt;th&gt;Controls&lt;/th&gt;
&lt;th&gt;Trap errors that are the naive answer&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Claude Haiku 4.5&lt;/td&gt;
&lt;td&gt;4%&lt;/td&gt;
&lt;td&gt;92%&lt;/td&gt;
&lt;td&gt;46 / 48&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Grok 4.20 (non-reasoning)&lt;/td&gt;
&lt;td&gt;18%&lt;/td&gt;
&lt;td&gt;96%&lt;/td&gt;
&lt;td&gt;37 / 41&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GPT-5.4 nano&lt;/td&gt;
&lt;td&gt;6%&lt;/td&gt;
&lt;td&gt;58%&lt;/td&gt;
&lt;td&gt;29 / 47&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GPT-5.4 mini&lt;/td&gt;
&lt;td&gt;34%&lt;/td&gt;
&lt;td&gt;92%&lt;/td&gt;
&lt;td&gt;31 / 33&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gemini 3.1 Flash Lite&lt;/td&gt;
&lt;td&gt;34%&lt;/td&gt;
&lt;td&gt;100%&lt;/td&gt;
&lt;td&gt;33 / 33&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gemini 3.5 Flash Lite&lt;/td&gt;
&lt;td&gt;34%&lt;/td&gt;
&lt;td&gt;96%&lt;/td&gt;
&lt;td&gt;33 / 33&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Qwen3 Coder 480B&lt;/td&gt;
&lt;td&gt;0%&lt;/td&gt;
&lt;td&gt;34%&lt;/td&gt;
&lt;td&gt;21 / 22&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gemini 2.5 Flash&lt;/td&gt;
&lt;td&gt;62%&lt;/td&gt;
&lt;td&gt;96%&lt;/td&gt;
&lt;td&gt;18 / 18&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Qwen3 Next Thinking&lt;/td&gt;
&lt;td&gt;64%&lt;/td&gt;
&lt;td&gt;98%&lt;/td&gt;
&lt;td&gt;15 / 15&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GPT-5.6 Luna&lt;/td&gt;
&lt;td&gt;70%&lt;/td&gt;
&lt;td&gt;100%&lt;/td&gt;
&lt;td&gt;14 / 15&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Grok 4.20 Reasoning&lt;/td&gt;
&lt;td&gt;84%&lt;/td&gt;
&lt;td&gt;100%&lt;/td&gt;
&lt;td&gt;8 / 8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gemma 4 31B&lt;/td&gt;
&lt;td&gt;90%&lt;/td&gt;
&lt;td&gt;100%&lt;/td&gt;
&lt;td&gt;5 / 5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Claude Sonnet 5&lt;/td&gt;
&lt;td&gt;96%&lt;/td&gt;
&lt;td&gt;100%&lt;/td&gt;
&lt;td&gt;2 / 2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gemma 4 26B&lt;/td&gt;
&lt;td&gt;98%&lt;/td&gt;
&lt;td&gt;98%&lt;/td&gt;
&lt;td&gt;1 / 1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gemini 3 Flash, 3.6 Flash, 3.7 Flash, 3.8 Flash, GLM-5&lt;/td&gt;
&lt;td&gt;100%&lt;/td&gt;
&lt;td&gt;100%&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&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%2Fc3h0ecr5fma986p7c7fm.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%2Fc3h0ecr5fma986p7c7fm.png" alt="Trap vs. control accuracy for the 19 pre-registered models" width="800" height="507"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The same chart with the 24-model extension added: &lt;a href="https://github.com/hvaler/deadline-math/blob/main/docs/img/pairs.png" rel="noopener noreferrer"&gt;pairs.png&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Full per-model tables with Wilson intervals and exact McNemar p-values, pre-registered cohort, and extension kept separate: &lt;a href="https://github.com/hvaler/deadline-math/blob/main/benchmark/resultados/RESULTS.md" rel="noopener noreferrer"&gt;RESULTS.md&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Secondary extension (logged as a deviation before running it, reported separately):&lt;/strong&gt; once quota allowed, I ran the same set on 24 more models, many of them the most expensive ones, and the five Kaggle added on October 6. The pattern holds (mean penalty +22.6 points, CI +19.7 to +25.4; &lt;strong&gt;308 of 321&lt;/strong&gt; extractable trap errors are the naive answer), with a clear split. Shown below: the two Claude lines and the models with no penalty; all 24 rows are in RESULTS.md.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Traps&lt;/th&gt;
&lt;th&gt;Controls&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Claude Sonnet 4.5&lt;/td&gt;
&lt;td&gt;6%&lt;/td&gt;
&lt;td&gt;100%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Claude Sonnet 4.6&lt;/td&gt;
&lt;td&gt;20%&lt;/td&gt;
&lt;td&gt;96%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Claude Sonnet 5 (pre-registered)&lt;/td&gt;
&lt;td&gt;96%&lt;/td&gt;
&lt;td&gt;100%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Claude Sonnet 5.5&lt;/td&gt;
&lt;td&gt;100%&lt;/td&gt;
&lt;td&gt;100%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Claude Opus 4.5&lt;/td&gt;
&lt;td&gt;22%&lt;/td&gt;
&lt;td&gt;82%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Claude Opus 4.6&lt;/td&gt;
&lt;td&gt;46%&lt;/td&gt;
&lt;td&gt;90%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Claude Opus 4.7&lt;/td&gt;
&lt;td&gt;76%&lt;/td&gt;
&lt;td&gt;90%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Claude Opus 4.8&lt;/td&gt;
&lt;td&gt;78%&lt;/td&gt;
&lt;td&gt;100%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Claude Opus 5&lt;/td&gt;
&lt;td&gt;96%&lt;/td&gt;
&lt;td&gt;90%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Claude Opus 5.5&lt;/td&gt;
&lt;td&gt;100%&lt;/td&gt;
&lt;td&gt;100%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Qwen3 235B&lt;/td&gt;
&lt;td&gt;0%&lt;/td&gt;
&lt;td&gt;88%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GPT-5.5, GPT-5.6 Sol/Terra, GPT-6 Astra, GPT-6 Sol, GPT-6.1 Sol, Gemini 3.1 Pro, Gemini 3.5 Flash&lt;/td&gt;
&lt;td&gt;100%&lt;/td&gt;
&lt;td&gt;98–100%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;So this is not "small models fail, big models pass". Some flagship models still carry the habit, and some smaller ones (Gemini 3.x Flash, Gemma 4 26B, GLM-5) do not. Within each Claude line, trap accuracy is higher in each later release I tested: Sonnet 6% → 20% → 96% → 100% (4.5 to 5.5) and Opus 22% → 46% → 76% → 78% → 96% → 100% (4.5 to 5.5). Each model ran once, so the gap between 4.7 and 4.8 is within run-to-run noise, and Opus 5 even scores slightly &lt;em&gt;lower&lt;/em&gt; on the controls (90%, not significant, p = 0.45). The newest generation tested here (Claude Opus 5.5 and Sonnet 5.5, GPT-6 Sol, and GPT-6.1 Sol) makes no trap errors at all.&lt;/p&gt;

&lt;p&gt;Read the Haiku row again: it gets the control right 92% of the time and the &lt;em&gt;same sentence on its trap date&lt;/em&gt; right 4% of the time, and when it is wrong, it is wrong by exactly the hour you would predict.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. The hard set separates the top models in specific places
&lt;/h3&gt;

&lt;p&gt;On the exploratory hard set, the top models finally diverge, and again the wrong answers are not random. Given &lt;code&gt;2026-10-25T02:30:00Z&lt;/code&gt;, ninety minutes after Europe left summer time (01:00 UTC), &lt;strong&gt;all 12&lt;/strong&gt; models that failed in direct mode (and 11 of 12 in reasoned mode) answered the same thing: 04:30 instead of 03:30, as if Madrid were still on summer time. Given a Unix timestamp, the most common wrong answer (5 models in direct mode, 7 in reasoned) was the same one, exactly one day early. Durations crossing a change got 0 of 3 from 11 models in direct mode, including Claude Haiku 4.5, Sonnet 4.5 and Opus 4.5, GPT-5.4 mini and nano, both Flash Lite models, and Grok 4.20 without reasoning.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Temperature 0 is not a fixed answer
&lt;/h3&gt;

&lt;p&gt;Because Kaggle's public leaderboard only shows the latest version of each task, I re-ran almost every model on the final versions, with the same prompts. That gave me a free reliability test: &lt;strong&gt;106 pairs of runs&lt;/strong&gt; of the same model on the same task. They agree on whether each case is right or wrong only &lt;strong&gt;92.1%&lt;/strong&gt; of the time; a model's score moves by 4.4 points on average between runs, and by up to 36 points on the 11-case hard set. Differences between close neighbors on a single-run leaderboard are noise, which is why the confirmatory claim rests on 50 pairs pooled across models, not on any one model's rank.&lt;/p&gt;

&lt;h3&gt;
  
  
  What surprised me, and what I would measure next
&lt;/h3&gt;

&lt;p&gt;What surprised me most is the Sonnet 4.5 row: a flagship model, perfect on the controls, failing 47 of 50 traps, and always in the same direction. And then how cleanly it disappears: the newest models in the same family make no trap errors at all. Next I would measure:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Repeated runs and other temperatures&lt;/strong&gt; to put real error bars on the per-model numbers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Other languages and readers outside Europe and North America&lt;/strong&gt; (Brazil, Chile, Australia), whose clock changes fall on yet other dates.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Agents with a clock tool&lt;/strong&gt;: Does giving the model a time-zone tool remove the bias, or does it still answer from habit without calling it?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What it changed in how I think about these models
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A model that &lt;strong&gt;states&lt;/strong&gt; the right rule can still &lt;strong&gt;apply&lt;/strong&gt; the habitual one. Reading the explanation is not verification.&lt;/li&gt;
&lt;li&gt;The failure is predictable, which makes it fixable: extract the date, time, and zone with the model, then compute with a time-zone library, and show the source next to the result. Never let free text be the source of truth for a deadline.&lt;/li&gt;
&lt;li&gt;The weeks around clock changes are a small, cheap regression test for any agent that touches calendars.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Limits
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Runs at temperature 0 are not deterministic (finding 6): differences of a few cases between models are noise.&lt;/li&gt;
&lt;li&gt;The cohort is the set of models that completed; quota and availability decide who is missing.&lt;/li&gt;
&lt;li&gt;The hard set is exploratory. Only the pairs set is confirmatory, and only for the 19 pre-registered models; the replication and the 24-model extension are secondary.&lt;/li&gt;
&lt;li&gt;Confidence intervals on the pairs resample the 50 cases with the cohort fixed; they do not cover other models or reruns. "Exactly one hour" shares are over misses with an extractable time; misses without an answer line are counted as failures but not classified.&lt;/li&gt;
&lt;li&gt;The score measures whether a correct time can be extracted, not strict formatting; strict one-line compliance is reported separately (793/860 and 424/473 in direct mode).&lt;/li&gt;
&lt;li&gt;English prompts only; readers in a handful of cities.&lt;/li&gt;
&lt;li&gt;The model list is the one Kaggle offered by October 6, 2026; the five models added after October 3 were run in a reopening of the data freeze, logged in the pre-registration, and only appear in secondary analyses.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  My Benchmark
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Kaggle benchmark:&lt;/strong&gt; &lt;a href="https://www.kaggle.com/benchmarks/hugovalerrojas/deadline-mat" rel="noopener noreferrer"&gt;kaggle.com/benchmarks/hugovalerrojas/deadline-mat&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Tasks: &lt;a href="https://www.kaggle.com/benchmarks/tasks/hugovalerrojas/deadline-math-pairs-direct" rel="noopener noreferrer"&gt;deadline-math-pairs-direct&lt;/a&gt; (pre-registered), &lt;a href="https://www.kaggle.com/benchmarks/tasks/hugovalerrojas/deadline-math-direct" rel="noopener noreferrer"&gt;deadline-math-direct&lt;/a&gt;, &lt;a href="https://www.kaggle.com/benchmarks/tasks/hugovalerrojas/deadline-math-reasoned" rel="noopener noreferrer"&gt;deadline-math-reasoned&lt;/a&gt;, &lt;a href="https://www.kaggle.com/benchmarks/tasks/hugovalerrojas/deadline-math-hard-direct" rel="noopener noreferrer"&gt;deadline-math-hard-direct&lt;/a&gt;, &lt;a href="https://www.kaggle.com/benchmarks/tasks/hugovalerrojas/deadline-math-hard-reasoned" rel="noopener noreferrer"&gt;deadline-math-hard-reasoned&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Code, raw runs and analysis: &lt;a href="https://github.com/hvaler/deadline-math" rel="noopener noreferrer"&gt;https://github.com/hvaler/deadline-math&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Cost: &lt;strong&gt;$0 to me.&lt;/strong&gt; Every call, including local pilots, went through Kaggle's Model Proxy within the free quota. The proxy reported a nominal $1.75 for the 608 local pilot calls; the leaderboard shows an estimated cost per model.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Built with the Kaggle Benchmarks SDK. AI assistance (Claude) was used for the code, the analysis, and the drafting of this post; I chose the problem, made the design decisions, and reviewed every claim. Every number above comes from the published runs.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>kagglechallenge</category>
      <category>machinelearning</category>
      <category>ai</category>
    </item>
    <item>
      <title>The Geometry Measures, the AI Teaches: An Agent That Verifies Descriptive-Geometry Constructions, with the Google GenAI SDK, Vertex AI &amp; OpenCV</title>
      <dc:creator>Hugo Valer</dc:creator>
      <pubDate>Wed, 19 Aug 2026 06:34:55 +0000</pubDate>
      <link>https://dev.to/hugo_valer_79d0d94e00804b/the-geometry-measures-the-ai-teaches-building-an-art-studio-tutor-with-adk-vertex-ai-opencv-551m</link>
      <guid>https://dev.to/hugo_valer_79d0d94e00804b/the-geometry-measures-the-ai-teaches-building-an-art-studio-tutor-with-adk-vertex-ai-opencv-551m</guid>
      <description>&lt;h2&gt;
  
  
  1. The origin: a discipline that defines correctness and never measures it
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Descriptive geometry&lt;/strong&gt; — &lt;em&gt;sistemas de representación&lt;/em&gt;, the tradition Gaspard Monge formalised in&lt;br&gt;
the 1790s — is a first-year subject in architecture, engineering and animation degrees. It has a&lt;br&gt;
property most drawing subjects do not: &lt;strong&gt;correctness is objective.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;An isometric axis is at 30° or it is not. A point's plan lies on the reference line dropped from its&lt;br&gt;
elevation or it does not. A rabatment recovers the true length or it does not. Nothing here depends&lt;br&gt;
on an examiner's taste, and the check is itself a construction rather than an opinion. The&lt;br&gt;
assessment rules reflect that: the Universidad de Granada requires a &lt;strong&gt;minimum of 5/10 in each block&lt;br&gt;
independently&lt;/strong&gt;, and the Universidad de Salamanca states plainly that &lt;em&gt;"es necesario superar cada&lt;br&gt;
bloque de forma independiente"&lt;/em&gt;. You cannot compensate a failed system with a strong one, because&lt;br&gt;
these are not matters of degree.&lt;/p&gt;

&lt;p&gt;So I went and read the syllabi — eighteen published sources across Spanish public engineering and&lt;br&gt;
architecture schools, international animation programmes, and open courseware. The finding is in&lt;br&gt;
&lt;a href="//PEDAGOGY.md"&gt;&lt;code&gt;docs/PEDAGOGY.md&lt;/code&gt;&lt;/a&gt;, and it is this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Not one of them states a numerical tolerance.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Nowhere does a figure in degrees or millimetres appear as a pass mark. The closest any source comes&lt;br&gt;
is a Canadian animation degree that grades &lt;em&gt;"composition, perspective and colour, with speed,&lt;br&gt;
**accuracy&lt;/em&gt;* and dexterity"* — accuracy as a graded outcome of a four-year honours degree, with the&lt;br&gt;
curriculum never saying how accurate.&lt;/p&gt;

&lt;p&gt;The discipline defines correctness exactly, and then hands the checking to a person with a set&lt;br&gt;
square at the end of a stack of plates. Meanwhile a general-purpose multimodal model asked to&lt;br&gt;
critique a drawing will happily invent the number — &lt;em&gt;"your angle is off by about 15 degrees"&lt;/em&gt; — with&lt;br&gt;
no spatial ground truth behind it at all.&lt;/p&gt;

&lt;p&gt;Atelier sits in that gap, and the scope is narrow on purpose:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;It automates the objective verification the discipline already defines. It does not invent a new&lt;br&gt;
criterion.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The invariant the whole system is built on:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"The geometry measures, the AI teaches, the student grows." (ADR-001)&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  2. Architecture: three systems, three kinds of reference
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                              ATELIER ARCHITECTURE

 ┌────────────────────────┐      ┌──────────────────────────────────────────────┐
 │  Atelier.Web           │      │  Vision gate — Gemini 3.5 Flash (Vertex AI)  │
 │  Blazor Server/.NET 10 │ ───&amp;gt; │  Is this an exercise at all?                 │
 │  - 3-step flow         │      │  Conic / axonometric / orthographic?         │
 │  - per-system viewers  │      └──────────────────────────────────────────────┘
 │  - append-only history │                            │
 └────────────────────────┘        ┌───────────────────┼───────────────────┐
             ▲                     ▼                   ▼                   ▼
             │            ┌────────────────┐  ┌────────────────┐  ┌────────────────┐
             │            │ geometry.py    │  │ axonometry.py  │  │ dihedral.py    │
             │            │ CONIC          │  │ AXONOMETRIC    │  │ ORTHOGRAPHIC   │
             │            │ RANSAC VPs     │  │ fixed axes     │  │ ground line +  │
             │            │ k = 1, 2       │  │ 30 / 90 / 150  │  │ correspondence │
             │            └────────────────┘  └────────────────┘  └────────────────┘
             │                     └───────────────────┼───────────────────┘
             │                                         ▼
 ┌────────────────────────┐      ┌──────────────────────────┐   ┌────────────────────┐
 │  Collaborative loop    │ &amp;lt;─── │  Anti-hallucination      │ &amp;lt;─│  Gemini 3.5 Flash  │
 │  ASK / GUIDE           │      │  validator               │   │  Two-plane critique│
 │  CAPTURE / ADAPT       │      │  measured_values()       │   │  Level-aware rubric│
 └────────────────────────┘      └──────────────────────────┘   └────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Atelier measures &lt;strong&gt;three of the four systems of representation&lt;/strong&gt;. The fourth, contoured planes&lt;br&gt;
(&lt;em&gt;planos acotados&lt;/em&gt;), needs the numeric annotations read off the page — OCR rather than line geometry — and is documented&lt;br&gt;
as not implemented.&lt;/p&gt;

&lt;p&gt;What makes them worth having together is that they are not one tool three times. &lt;strong&gt;They differ in&lt;br&gt;
where the reference comes from&lt;/strong&gt;, and that determines how far each measurement can be trusted:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;System&lt;/th&gt;
&lt;th&gt;Where the reference comes from&lt;/th&gt;
&lt;th&gt;Trust&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Conic&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Inferred.&lt;/strong&gt; RANSAC estimates a vanishing point from the student's own lines&lt;/td&gt;
&lt;td&gt;Weakest — a consistently wrong drawing yields a vanishing point that agrees with it, and the reported error shrinks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Orthographic&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Read off the page.&lt;/strong&gt; The ground line is a line the student drew&lt;/td&gt;
&lt;td&gt;Middle — nothing is guessed, but a crooked ground line skews everything, so its tilt is reported as a figure in its own right&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Axonometric&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Given.&lt;/strong&gt; The axes are constants of the projection system&lt;/td&gt;
&lt;td&gt;Strongest — nothing is estimated at all&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;That ranking is stated in the documentation rather than hidden, and it is measurable: in the golden&lt;br&gt;
case an error injected at exactly 6° comes back at &lt;strong&gt;6.00°&lt;/strong&gt;, asserted to within 0.05°. The&lt;br&gt;
perspective suite cannot hold a bound that tight, and says so.&lt;/p&gt;

&lt;h3&gt;
  
  
  The two-plane critique
&lt;/h3&gt;

&lt;p&gt;Every critique is split into two planes that may not mix:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Plane A — measured findings.&lt;/strong&gt; Every figure comes from OpenCV, verbatim.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Plane B — studio observations.&lt;/strong&gt; Line weight, spatial legibility, cleanliness. &lt;strong&gt;Forbidden a
number at all.&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;An &lt;strong&gt;anti-hallucination validator&lt;/strong&gt; intercepts the model's answer. It asks the analysis what it&lt;br&gt;
measured — &lt;code&gt;measured_values()&lt;/code&gt; — rather than reading named fields, which is what lets a new&lt;br&gt;
projection system be added without silently arriving unguarded. Any figure the model did not get&lt;br&gt;
from that set is rejected and regenerated with corrective feedback.&lt;/p&gt;

&lt;p&gt;The prose gate is bilingual for a reason that is easy to miss: a detector that only recognises&lt;br&gt;
&lt;code&gt;degrees&lt;/code&gt; stops being a gate the moment the interface is translated. It recognises &lt;code&gt;grados&lt;/code&gt; too.&lt;/p&gt;

&lt;h3&gt;
  
  
  Two models, two jobs
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Gemini 3.5 Flash&lt;/strong&gt; (Vertex AI, &lt;code&gt;europe-west3&lt;/code&gt;) looks at the photograph twice: once as a gate —
&lt;em&gt;is this an exercise, and which system?&lt;/em&gt; — and once to write the critique.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gemma 4&lt;/strong&gt; (&lt;code&gt;gemma-4-26b-a4b-it&lt;/code&gt;, via the Gemini API — it is not published on Vertex AI) reads
the student's own description and infers which perspective they meant.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When the two disagree, &lt;strong&gt;the words do not win.&lt;/strong&gt; An early version re-measured on the router's&lt;br&gt;
say-so, and a one-point box described as "the corner of a building" came back as two-point with 29.9°&lt;br&gt;
of average error. The measurement is evidence; the description is a claim. Atelier now reports the&lt;br&gt;
disagreement and changes nothing.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. The four verbs of "The Collaborative Partner"
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;ASK&lt;/strong&gt; — before analysing: &lt;em&gt;"What were you practising today? Which part felt hardest?"&lt;/em&gt; The
answers set the register of the critique. They never change the measurement.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GUIDE&lt;/strong&gt; — the next exercise comes from a ladder documented in published curricula, not invented
to fill a JSON field. Rungs the engine cannot yet assess are recorded as gaps and deliberately
not prescribed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CAPTURE&lt;/strong&gt; — explicit feedback (&lt;code&gt;helpful: bool&lt;/code&gt; + note) persisted as an immutable event in
Firestore (ADR-005).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ADAPT&lt;/strong&gt; — the profile is derived from the event stream, never edited. Note that the profile is a
&lt;strong&gt;difficulty level&lt;/strong&gt;, not a person: it sets the rubric's register and nothing else.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  4. Asynchronous pipeline and Cloud Run deployment
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Async-first ingestion&lt;/strong&gt; — a photograph dropped into a private Cloud Storage inbox
(&lt;code&gt;atelier-hack-inbox/{studentId}/&lt;/code&gt;) fires an Eventarc CloudEvent at the Cloud Run agent, which
downloads the object, measures it and stores the result with nobody touching the app.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Weekly digest&lt;/strong&gt; — Cloud Scheduler aggregates the week and prescribes a three-day practice plan.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The measurement API&lt;/strong&gt; — &lt;code&gt;POST /api/analyze&lt;/code&gt;, &lt;code&gt;/api/analyze/axonometric&lt;/code&gt;, &lt;code&gt;/api/analyze/dihedral&lt;/code&gt;,
plus &lt;code&gt;/api/router/gate&lt;/code&gt; and &lt;code&gt;/api/router/classify&lt;/code&gt; for the two routing decisions, and
&lt;code&gt;GET /api/students/{id}/exercises&lt;/code&gt; for the student's own history.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Production hardening&lt;/strong&gt; — Cloud Run with .NET 10 (&lt;code&gt;KnownIPNetworks.Clear()&lt;/code&gt; for proxy header
termination) and Python FastAPI.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>python</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
