<?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: Jan Wangrat</title>
    <description>The latest articles on DEV Community by Jan Wangrat (@janwan2003).</description>
    <link>https://dev.to/janwan2003</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%2F4098999%2F85c38fd9-e9e7-4c2f-af1e-aff2b2477d70.jpg</url>
      <title>DEV Community: Jan Wangrat</title>
      <link>https://dev.to/janwan2003</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/janwan2003"/>
    <language>en</language>
    <item>
      <title>The bug that made my best-dates feature return nothing at 31 people</title>
      <dc:creator>Jan Wangrat</dc:creator>
      <pubDate>Fri, 28 Aug 2026 13:56:37 +0000</pubDate>
      <link>https://dev.to/janwan2003/the-bug-that-made-my-best-dates-feature-return-nothing-at-31-people-2e4a</link>
      <guid>https://dev.to/janwan2003/the-bug-that-made-my-best-dates-feature-return-nothing-at-31-people-2e4a</guid>
      <description>&lt;p&gt;I built a small thing for picking the dates of a group trip: everyone taps the days they are free, and it ranks the stretches of days that work for the most people. No accounts, just a link you share.&lt;/p&gt;

&lt;p&gt;The first version of that ranking enumerated every subset of participants:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&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;mask&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="nx"&gt;mask&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&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;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="nx"&gt;mask&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;// find the days everyone in this subset is free&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two problems. The second one is the interesting one.&lt;/p&gt;

&lt;p&gt;2^n iterations locks up the tab somewhere around twenty people. Annoying, expected, fixable later.&lt;/p&gt;

&lt;p&gt;At n = 31, &lt;code&gt;1 &amp;lt;&amp;lt; 31&lt;/code&gt; is negative. Bitwise operators in JS coerce to int32, the sign bit flips, and you get -2147483648. So &lt;code&gt;mask &amp;lt; (1 &amp;lt;&amp;lt; 31)&lt;/code&gt; is false on the very first check, the loop body never runs, and the function returns an empty list. No error, no warning. The feature quietly stops existing.&lt;/p&gt;

&lt;p&gt;Worse than that: past 31 participants it didn't fail, it answered wrong. On a 35-person test trip where all 35 people were free for the same five days, it offered that range to 6 of them.&lt;/p&gt;

&lt;p&gt;The fix wasn't a bigger loop. The subsets were never the interesting objects. For any given stretch of days, the people who can make all of it are already determined: they are the intersection of who is free on each day. So walk the ranges and carry that intersection.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// availability[day] is a BigInt bitmask of who is free that day&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;members&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;availability&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;start&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;day&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;start&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="nx"&gt;day&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nx"&gt;end&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;day&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="nx"&gt;members&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;=&lt;/span&gt; &lt;span class="nx"&gt;availability&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;day&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;Emit a candidate wherever the running intersection is about to shrink, and every set you emit is maximal for its range by construction. That also deleted a separate "same dates but more people" dominance check I no longer needed.&lt;/p&gt;

&lt;p&gt;BigInt instead of a 32-bit number is the part that actually matters. Number would have moved the cliff to 53 and left the same class of bug sitting there. Sixty people across ninety days now answers in under three seconds.&lt;/p&gt;

&lt;p&gt;Two things I took away.&lt;/p&gt;

&lt;p&gt;Silent empty results are worse than exceptions. The 2^n slowness showed up the first time I tested with a realistic group. The n = 31 cliff needed someone to have 31 friends.&lt;/p&gt;

&lt;p&gt;And: bitwise operators in JavaScript are int32. I knew that. I still wrote &lt;code&gt;1 &amp;lt;&amp;lt; n&lt;/code&gt; with n coming from user data.&lt;/p&gt;

&lt;p&gt;The rest of the stack is deliberately boring. React on Cloudflare Pages, Pages Functions for the API, D1 for storage, no auth provider, no accounts at all - identity is a name you type plus possession of the link.&lt;/p&gt;

&lt;p&gt;It's at &lt;a href="https://wegowhen.com" rel="noopener noreferrer"&gt;wegowhen.com&lt;/a&gt; if you want to poke at it, and the source is &lt;a href="https://github.com/janwan2003/trip-planner" rel="noopener noreferrer"&gt;on GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Fix and write-up done with Claude Code.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
