<?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: Joel</title>
    <description>The latest articles on DEV Community by Joel (@socialfuel).</description>
    <link>https://dev.to/socialfuel</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%2F4063278%2F46a763d3-dece-470a-b508-f6a01e08f379.jpg</url>
      <title>DEV Community: Joel</title>
      <link>https://dev.to/socialfuel</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/socialfuel"/>
    <language>en</language>
    <item>
      <title>Our password reset links kept expiring. The bug only happened if you had two tabs open.</title>
      <dc:creator>Joel</dc:creator>
      <pubDate>Fri, 07 Aug 2026 10:20:11 +0000</pubDate>
      <link>https://dev.to/socialfuel/our-password-reset-links-kept-expiring-the-bug-only-happened-if-you-had-two-tabs-open-e46</link>
      <guid>https://dev.to/socialfuel/our-password-reset-links-kept-expiring-the-bug-only-happened-if-you-had-two-tabs-open-e46</guid>
      <description>&lt;p&gt;A user told us their password reset link was expired. It was about four minutes old.&lt;/p&gt;

&lt;p&gt;I clicked it myself. Worked fine. Asked them to try again. Expired again.&lt;/p&gt;

&lt;p&gt;That went on longer than I want to admit, because the bug does not reproduce unless you already have the app open in another tab. I never do while testing. Our users always do.&lt;/p&gt;

&lt;h2&gt;
  
  
  What was actually happening
&lt;/h2&gt;

&lt;p&gt;Supabase sends the session back in the URL fragment. You land on something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://app.example.com/#access_token=eyJhbG...&amp;amp;type=recovery
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The client reads that fragment, exchanges it for a session, and strips it from the URL. The important word is &lt;strong&gt;asynchronously&lt;/strong&gt;. It does not happen on the same tick your app boots.&lt;/p&gt;

&lt;p&gt;We had a bit of code at boot that tidied the URL. Nothing exotic:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// what we had&lt;/span&gt;
&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;history&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replaceState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pathname&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That runs on mount. If it wins the race, the fragment is gone before Supabase ever reads it. No session, no recovery event, and the reset page renders "That link has expired" on a link that was perfectly valid a second ago.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the second tab matters
&lt;/h2&gt;

&lt;p&gt;This is the part I found genuinely interesting.&lt;/p&gt;

&lt;p&gt;supabase-js coordinates token refresh across tabs using &lt;code&gt;navigator.locks&lt;/code&gt;. With one tab there is no contention and the exchange finishes fast, usually before React has even mounted. Our &lt;code&gt;replaceState&lt;/code&gt; lost the race and everything worked.&lt;/p&gt;

&lt;p&gt;Open a second tab and the lock is contended. The exchange waits. In our logs GoTrue was saying:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Lock not released within 5000ms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It recovers, but by then it is whole seconds behind. Our &lt;code&gt;replaceState&lt;/code&gt; had fired ages ago and eaten the token.&lt;/p&gt;

&lt;p&gt;So the bug was not intermittent at all. It was deterministic. It just depended on a variable I was not thinking of as a variable.&lt;/p&gt;

&lt;p&gt;Worth saying plainly, because it cost me an afternoon: &lt;strong&gt;"I cannot reproduce it" usually means my environment differs from theirs in a way I have not identified yet.&lt;/strong&gt; It rarely means the user is wrong.&lt;/p&gt;

&lt;h2&gt;
  
  
  We had two of them
&lt;/h2&gt;

&lt;p&gt;Once I knew what to look for, there was a second offender. A boot routine that normalised query parameters, on a blind 1.5 second timer. Same effect, slightly later, and it explained why a couple of the fixes I tried seemed to half work.&lt;/p&gt;

&lt;p&gt;If you have written one URL scrub you have probably written two. Grep for &lt;code&gt;replaceState&lt;/code&gt; and &lt;code&gt;pushState&lt;/code&gt; before you decide you are done.&lt;/p&gt;

&lt;h2&gt;
  
  
  The rule that fixed it
&lt;/h2&gt;

&lt;p&gt;Nothing may rewrite the URL while the fragment still carries unconsumed tokens.&lt;/p&gt;

&lt;p&gt;In practice that means one of two things. Either wait until the hash is empty, or only touch your own markers and put the fragment back exactly as you found it. We went with the second because it does not need a timer at all:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;callbackType&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;pathname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;search&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;hash&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;search&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;recovery=1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;URLSearchParams&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;search&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;recovery&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;                 &lt;span class="c1"&gt;// our marker, ours to remove&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;qs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;history&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replaceState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;pathname&lt;/span&gt;&lt;span class="p"&gt;}${&lt;/span&gt;&lt;span class="nx"&gt;qs&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="s2"&gt;`?&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;qs&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;}${&lt;/span&gt;&lt;span class="nx"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;   &lt;span class="c1"&gt;// fragment goes back untouched&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Supabase strips the fragment itself once it has consumed it. You do not need to clean up after it. Let it finish.&lt;/p&gt;

&lt;p&gt;We also kept a second net, because the exchange can land after mount:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;supabase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onAuthStateChange&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;PASSWORD_RECOVERY&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setCallbackType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;recovery&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;history&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replaceState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pathname&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;// safe now&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;That &lt;code&gt;replaceState&lt;/code&gt; is fine, because by the time the event fires the token has already been used.&lt;/p&gt;

&lt;h2&gt;
  
  
  The bit that bites you next
&lt;/h2&gt;

&lt;p&gt;There is a follow-on problem that is easy to walk straight into once you have fixed the first one.&lt;/p&gt;

&lt;p&gt;If anything rewrites the URL at boot, then any code reading &lt;code&gt;window.location&lt;/code&gt; later is reading whatever survived, not what the user arrived with. We were checking for a recovery marker after our own scrub had already removed it.&lt;/p&gt;

&lt;p&gt;The fix is to snapshot at module evaluation, before React does anything:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bootHash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;undefined&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hash&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bootSearch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;undefined&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;search&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then read &lt;code&gt;bootSearch&lt;/code&gt; and &lt;code&gt;bootHash&lt;/code&gt; everywhere, never live &lt;code&gt;location&lt;/code&gt;. Same idea applies to UTM parameters, referral codes, anything you care about that arrives in the URL and might get tidied away.&lt;/p&gt;

&lt;p&gt;We also route expired links to a real screen with a resend button instead of dumping people on the dashboard with no explanation. Some of those links genuinely are expired, and "nothing happened" is a terrible answer.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I would take from it
&lt;/h2&gt;

&lt;p&gt;If you are using Supabase auth in a SPA, go and grep for &lt;code&gt;replaceState&lt;/code&gt; right now. If any of it runs at boot without checking the hash, you have this bug. It will look intermittent, it will not reproduce on your machine, and it only shows up on the flow where users are already frustrated.&lt;/p&gt;

&lt;p&gt;Two tabs. That was the whole thing.&lt;/p&gt;




&lt;p&gt;I build &lt;a href="https://socialfuel.io" rel="noopener noreferrer"&gt;SOCIALFUEL&lt;/a&gt;, which pulls the live ads any brand is running and breaks down why they work. This one came out of our own auth flow, and I would rather write it up than have someone else lose the same afternoon.&lt;/p&gt;

</description>
      <category>supabase</category>
      <category>react</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Prompt engineering couldn't fix this LLM bug. 20 lines of binary parsing did.</title>
      <dc:creator>Joel</dc:creator>
      <pubDate>Wed, 05 Aug 2026 02:23:37 +0000</pubDate>
      <link>https://dev.to/socialfuel/prompt-engineering-couldnt-fix-this-llm-bug-20-lines-of-binary-parsing-did-3n37</link>
      <guid>https://dev.to/socialfuel/prompt-engineering-couldnt-fix-this-llm-bug-20-lines-of-binary-parsing-did-3n37</guid>
      <description>&lt;p&gt;New here (hey 👋) and wanted to share something. We recently made public an ad intel app we'd been using internally in our agency. The app/system runs video ads through Gemini to pull out a transcript, the hook, and a few timed moments. It works fairly well - especially for ideation. The transcription is genuinely accurate.&lt;/p&gt;

&lt;p&gt;A user opened a 2:22 video and saw a moment marked at &lt;strong&gt;3:37&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Not a rounding error. Fifty percent past the end of a video the user was looking at.&lt;/p&gt;

&lt;h2&gt;
  
  
  The part that makes it interesting
&lt;/h2&gt;

&lt;p&gt;The obvious guess is that the model didn't know how long the video was. That would be a reasonable bug and an easy fix.&lt;/p&gt;

&lt;p&gt;But in the &lt;em&gt;same JSON response&lt;/em&gt;, Gemini reported &lt;code&gt;duration_seconds&lt;/code&gt; correctly.&lt;/p&gt;

&lt;p&gt;We measured it properly on one ad, four identical runs, same file, same prompt:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Real duration: &lt;strong&gt;142.08 seconds&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;duration_seconds&lt;/code&gt; reported by the model: &lt;strong&gt;correct, every run&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Transcript timestamps: &lt;strong&gt;drifted past the end on 1 run in 4&lt;/strong&gt;, reaching &lt;code&gt;t=214&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The words were right. The clock was 50% long. The model was holding the correct duration and writing impossible timestamps anyway.&lt;/p&gt;

&lt;p&gt;That is not a knowledge problem. It's a consistency problem, and those don't respond to being asked nicely.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prompt hardening didn't work
&lt;/h2&gt;

&lt;p&gt;We tried the things you'd try. State the duration in the prompt. Tell it no timestamp may exceed that. Restate the constraint after the schema. Put it in caps.&lt;/p&gt;

&lt;p&gt;Failure rate went down. It didn't go to zero. A hardened run still drifted to &lt;code&gt;t=218&lt;/code&gt; on a 142-second video.&lt;/p&gt;

&lt;p&gt;This is where I'd argue the general lesson lives:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If a model can violate a constraint, prompting reduces how often it does. Only code makes it impossible.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For most output that trade is fine, because most output is hard to falsify. Nobody checks whether a "psychological driver" is really the third most important one.&lt;/p&gt;

&lt;p&gt;Timestamps are different. &lt;strong&gt;A timestamp is falsifiable in one click.&lt;/strong&gt; The user scrubs to 3:37 on a 2:22 video and the whole analysis loses credibility, including all the parts that were correct. One checkable wrong number poisons everything unverifiable around it.&lt;/p&gt;

&lt;p&gt;So we needed a ground truth the model couldn't wander away from.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ground truth: read it out of the file
&lt;/h2&gt;

&lt;p&gt;The video is already in memory as a &lt;code&gt;Buffer&lt;/code&gt; before it goes anywhere near the model. MP4 files carry their own duration in the &lt;code&gt;mvhd&lt;/code&gt; atom (movie header). No API call, no dependency, and &lt;code&gt;ffprobe&lt;/code&gt; isn't installed on our host anyway.&lt;/p&gt;

&lt;p&gt;The layout after the 4-byte &lt;code&gt;mvhd&lt;/code&gt; type is: version (1 byte), flags (3), then for version 0 — created (4), modified (4), timescale (4), duration (4). For version 1, the timestamps are 8 bytes and duration is 8.&lt;/p&gt;

&lt;p&gt;Duration in seconds is &lt;code&gt;duration / timescale&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;mp4DurationSeconds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;limit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&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="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// scan for the ASCII bytes 'm','v','h','d'&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="mh"&gt;0x6d&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&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="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="mh"&gt;0x76&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="mh"&gt;0x68&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="mh"&gt;0x64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;version&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&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="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;base&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// past 'mvhd' + version(1) + flags(3)&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;version&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="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;timescale&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readUInt32BE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;base&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;duration&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readBigUInt64BE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;base&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timescale&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="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;duration&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;return&lt;/span&gt; &lt;span class="nx"&gt;duration&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;timescale&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;timescale&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readUInt32BE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;base&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;duration&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readUInt32BE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;base&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timescale&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="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;duration&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;return&lt;/span&gt; &lt;span class="nx"&gt;duration&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;timescale&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// malformed atom, keep scanning for a valid one&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&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;Two deliberate choices worth explaining.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;We scan for the atom rather than walking the box tree.&lt;/strong&gt; Walking is more correct in principle. Scanning handles both faststart files (&lt;code&gt;moov&lt;/code&gt; at the front) and files with &lt;code&gt;moov&lt;/code&gt; at the end, without implementing a parser for a container format we only need one number out of.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A malformed atom keeps the loop going instead of throwing.&lt;/strong&gt; The four bytes &lt;code&gt;mvhd&lt;/code&gt; can appear inside compressed video data by coincidence. If you bail on the first match that doesn't parse, a random byte sequence takes down your duration check.&lt;/p&gt;

&lt;h2&gt;
  
  
  Then enforce it, rather than trusting the enforcement
&lt;/h2&gt;

&lt;p&gt;With a real ceiling, every timestamp gets validated server-side before it reaches the client. Same doctrine as validating any untrusted input, because that's what model output is.&lt;/p&gt;

&lt;p&gt;The interesting decisions were about what to do with a bad value, not how to spot one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Keep the words, drop the clock.&lt;/strong&gt; The transcription is accurate. Only the timing is untrustworthy. So an impossible timestamp is deleted and the text survives. Our transcript component already renders a blank gutter for a missing &lt;code&gt;t&lt;/code&gt;, so a stripped timestamp degrades into a clean script instead of a wrong number.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Null both ends of a pair, not just the bad one.&lt;/strong&gt; We track "curiosity loops" with an open and a close time. If the close is impossible, nulling only that one leaves a surviving open time next to a blank close, which renders as precision we don't have. Both go.&lt;/p&gt;

&lt;h2&gt;
  
  
  The bug inside the fix
&lt;/h2&gt;

&lt;p&gt;This one cost me an afternoon and it's pure JavaScript, nothing to do with AI.&lt;/p&gt;

&lt;p&gt;The first version coerced timestamps with &lt;code&gt;Number(x)&lt;/code&gt;. Looks harmless:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// WRONG&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;t&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;Number(null)&lt;/code&gt; is &lt;code&gt;0&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A model that &lt;em&gt;honestly&lt;/em&gt; returns &lt;code&gt;null&lt;/code&gt; for "I don't know when this happened" gets that turned into &lt;code&gt;0&lt;/code&gt;, which renders as &lt;strong&gt;0:00&lt;/strong&gt;, which then reads as a loop closing before it opens, which trips the validation that was supposed to be protecting us. An honest null became a confident lie in one implicit coercion.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;asSeconds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isFinite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&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;Caught by a unit test, thankfully, and not by a user. If you're sanitising LLM output, &lt;code&gt;null&lt;/code&gt; and &lt;code&gt;0&lt;/code&gt; mean completely different things and JavaScript will happily merge them for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Not all bad timestamps mean the same thing
&lt;/h2&gt;

&lt;p&gt;The last piece is the one I'd have got wrong without looking at the actual failures.&lt;/p&gt;

&lt;p&gt;The observed mode is a &lt;strong&gt;drifting tail&lt;/strong&gt;. The model transcribes accurately the whole way through, but its clock stretches as it goes, so the late chunks are impossible while every earlier timestamp is fine. Those early ones are good data and worth keeping.&lt;/p&gt;

&lt;p&gt;Scattered bad timestamps through the body are a different signal entirely. That means the timing pass itself is unreliable, and presenting a mix of right and wrong as though it were precise is worse than presenting nothing.&lt;/p&gt;

&lt;p&gt;So: a contiguous run of bad timestamps ending at the final chunk is treated as tail drift and trimmed. Anything else strips all timings.&lt;/p&gt;

&lt;p&gt;My first instinct was a percentage threshold, something like "if more than 25% are impossible, drop everything". That's wrong, and the reason is worth internalising:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The same failure would be judged differently depending on how many chunks the model happened to emit.&lt;/strong&gt; A five-chunk drift is 19% of a 26-chunk transcript and 28% of an 18-chunk one. Identical failure, opposite verdicts, decided by something you don't control. Threshold on the &lt;em&gt;shape&lt;/em&gt; of the failure, not its proportion.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'd take from this
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;A model can hold a fact and violate it in the same response.&lt;/strong&gt; Reporting the duration correctly told us nothing about whether it would respect it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prompting sets a tendency. Code sets a guarantee.&lt;/strong&gt; For anything a user can check in one click, you need the guarantee.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Find the ground truth in the artefact you already have.&lt;/strong&gt; The buffer was in memory the whole time. We were asking a language model for a number that was sitting in a binary header 20 lines of code away.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Partial output usually beats no output, if you're honest about which part you dropped.&lt;/strong&gt; The words were always right. Only the clock was wrong. Shipping an accurate transcript with no timestamps is better than shipping either a wrong timestamp or nothing at all.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;I build &lt;a href="https://socialfuel.io" rel="noopener noreferrer"&gt;SOCIALFUEL&lt;/a&gt;, which pulls the live ads any brand is running and decodes what makes them work. The video pipeline behind it is where this bug lived. If you're doing timed analysis on video with an LLM, I'd check your timestamps against the container before you trust them.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>typescript</category>
      <category>node</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
