<?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: desgh white</title>
    <description>The latest articles on DEV Community by desgh white (@desgh_white_7e4c654897816).</description>
    <link>https://dev.to/desgh_white_7e4c654897816</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%2F4020165%2F017e6d3a-173e-4404-87c6-42f2db79349b.png</url>
      <title>DEV Community: desgh white</title>
      <link>https://dev.to/desgh_white_7e4c654897816</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/desgh_white_7e4c654897816"/>
    <language>en</language>
    <item>
      <title>Keeping a Live Stream and Its Game State in Sync</title>
      <dc:creator>desgh white</dc:creator>
      <pubDate>Wed, 16 Sep 2026 11:59:25 +0000</pubDate>
      <link>https://dev.to/desgh_white_7e4c654897816/keeping-a-live-stream-and-its-game-state-in-sync-4j01</link>
      <guid>https://dev.to/desgh_white_7e4c654897816/keeping-a-live-stream-and-its-game-state-in-sync-4j01</guid>
      <description>&lt;p&gt;A video feed and a state channel travel over different paths with different buffering. If you render state the instant it arrives, the UI narrates the future: the result appears before the viewer sees it happen. Fixing that is mostly about sequencing, not speed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two clocks, one round
&lt;/h2&gt;

&lt;p&gt;Video is delayed by encoding, CDN and player buffer — typically several seconds. The WebSocket message is delayed by milliseconds. So state must be &lt;em&gt;held back&lt;/em&gt; to the stream, not pushed ahead of it.&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;STREAM_DELAY_MS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;player&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;buffered&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;
  &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;player&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;buffered&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;end&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;player&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentTime&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;
  &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;schedule&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="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;wait&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;showAtMs&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nc"&gt;STREAM_DELAY_MS&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
  &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;render&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="nx"&gt;wait&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;Server timestamps carry the intent (&lt;code&gt;showAtMs&lt;/code&gt;); the client aligns them to its own buffer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sequence numbers beat timestamps
&lt;/h2&gt;

&lt;p&gt;Clock skew makes wall-clock ordering unreliable. Give every state change a monotonic &lt;code&gt;seq&lt;/code&gt; per round and drop anything you have already applied:&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="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;applied&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;onMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;seq&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nx"&gt;applied&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;        &lt;span class="c1"&gt;// duplicate or out-of-order&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;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;seq&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;applied&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="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;resync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;roundId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// gap -&amp;gt; refetch&lt;/span&gt;
  &lt;span class="nx"&gt;applied&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;seq&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nf"&gt;schedule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;msg&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;The gap branch matters more than the duplicate branch: a missed transition leaves the UI confidently wrong, which is worse than a brief spinner.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reconnect by snapshot, not by replay
&lt;/h2&gt;

&lt;p&gt;After a disconnect, replaying the backlog re-animates events the viewer already missed. Fetch a snapshot of the current round instead, set &lt;code&gt;applied&lt;/code&gt; to its &lt;code&gt;seq&lt;/code&gt;, and resume the live channel from there. Backlogs are for audit logs; snapshots are for UIs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Make the states explicit
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;betting_open -&amp;gt; betting_closed -&amp;gt; spinning -&amp;gt; resolved&lt;/code&gt; as an enum, with illegal transitions rejected, keeps a late message from reopening a closed round. The same discipline that protects a payments ledger protects a round.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reference
&lt;/h2&gt;

&lt;p&gt;Live-dealer formats are the demanding case, since bets close while the wheel is already moving. Looking at how a live catalogue such as &lt;a href="https://crazytime-italian.com/" rel="noopener noreferrer"&gt;Crazy Time&lt;/a&gt; organizes its rounds and bet windows is a practical way to see which transitions have to be strictly ordered and which can tolerate a late arrival.&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaway
&lt;/h2&gt;

&lt;p&gt;Delay state to the stream, order by sequence rather than clock, resync from a snapshot, and forbid illegal transitions. The feed and the UI then tell the same story.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Money Rounding Without Silent Losses: Decimal, Half-Even and Idempotent Payouts</title>
      <dc:creator>desgh white</dc:creator>
      <pubDate>Wed, 16 Sep 2026 11:58:29 +0000</pubDate>
      <link>https://dev.to/desgh_white_7e4c654897816/money-rounding-without-silent-losses-decimal-half-even-and-idempotent-payouts-4add</link>
      <guid>https://dev.to/desgh_white_7e4c654897816/money-rounding-without-silent-losses-decimal-half-even-and-idempotent-payouts-4add</guid>
      <description>&lt;p&gt;Every payments codebase eventually meets the same bug: totals that disagree by a cent. It is never one dramatic failure — it is thousands of tiny roundings that drift apart, and the ledger notices before the tests do.&lt;/p&gt;

&lt;h2&gt;
  
  
  Floats are the wrong tool
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="mf"&gt;0.1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mf"&gt;0.2&lt;/span&gt;
&lt;span class="mf"&gt;0.30000000000000004&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;2.675&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="mf"&gt;2.67&lt;/span&gt;          &lt;span class="c1"&gt;# not 2.68 — 2.675 is not exactly representable
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Binary floating point cannot represent most decimal fractions, so the error compounds across every intermediate step. Use &lt;code&gt;Decimal&lt;/code&gt; and keep the scale explicit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;decimal&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ROUND_HALF_EVEN&lt;/span&gt;

&lt;span class="n"&gt;CENT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.01&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;to_cents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;quantize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CENT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rounding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;ROUND_HALF_EVEN&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why half-even, not half-up
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;ROUND_HALF_UP&lt;/code&gt; biases every tie upward. Over a large number of settlements that bias is a systematic drift in one direction. Banker's rounding (&lt;code&gt;ROUND_HALF_EVEN&lt;/code&gt;) sends ties to the nearest even digit, so the errors cancel instead of accumulating:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;to_cents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;.005&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10_000&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run that with both modes and compare the totals — the difference is the money your reconciliation job will chase.&lt;/p&gt;

&lt;h2&gt;
  
  
  Round once, at the boundary
&lt;/h2&gt;

&lt;p&gt;The rule that removes most bugs: compute at full precision, round exactly once when the value becomes an amount someone is paid. Rounding intermediate multiplications means the same total depends on evaluation order, which is how two services disagree about one number.&lt;/p&gt;

&lt;h2&gt;
  
  
  Make the payout idempotent
&lt;/h2&gt;

&lt;p&gt;Rounding correctly still leaves the retry problem: a timeout during payout is indistinguishable from a failure, and the naive retry pays twice.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;payout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;payout_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;cur&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;INSERT INTO payouts(id, user_id, amount_cents) VALUES (?, ?, ?) &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ON CONFLICT(id) DO NOTHING&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payout_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;to_cents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;cur&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rowcount&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;     &lt;span class="c1"&gt;# False = already paid, safe to ignore
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Store integer cents, derive the key from the settlement event rather than the request, and the retry becomes a no-op instead of a duplicate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reference
&lt;/h2&gt;

&lt;p&gt;Consumer-facing payment pages are a useful sanity check on all of this: a site like &lt;a href="https://true-fortunecasino.es/" rel="noopener noreferrer"&gt;play at True Fortune Casino&lt;/a&gt; lists deposit and withdrawal minimums per method, and those published limits are exactly the boundary values worth turning into test cases — the amounts where rounding, fees and minimums interact.&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaway
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;Decimal&lt;/code&gt; over float, half-even over half-up, round once at the boundary, and make the write idempotent. Four rules, and the cent-level drift stops being a recurring ticket.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Modeling Self-Exclusion as an Explicit State Machine</title>
      <dc:creator>desgh white</dc:creator>
      <pubDate>Tue, 18 Aug 2026 16:46:07 +0000</pubDate>
      <link>https://dev.to/desgh_white_7e4c654897816/modeling-self-exclusion-as-an-explicit-state-machine-3bi4</link>
      <guid>https://dev.to/desgh_white_7e4c654897816/modeling-self-exclusion-as-an-explicit-state-machine-3bi4</guid>
      <description>&lt;p&gt;Some product rules are too important to live as scattered &lt;code&gt;if&lt;/code&gt; checks. Account restrictions — cooling-off, self-exclusion, reactivation — are one of them: get the transitions wrong and you either trap a user or fail to honor a limit they set. A finite state machine makes the rules auditable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enumerate states and legal transitions
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;enum&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Enum&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;State&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Enum&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;ACTIVE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;active&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;COOLING_OFF&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cooling_off&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;     &lt;span class="c1"&gt;# short, timed, auto-reverts
&lt;/span&gt;    &lt;span class="n"&gt;EXCLUDED&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;excluded&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;           &lt;span class="c1"&gt;# long, cannot self-reverse
&lt;/span&gt;    &lt;span class="n"&gt;CLOSED&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;closed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="n"&gt;TRANSITIONS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;State&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ACTIVE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;State&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;COOLING_OFF&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;State&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EXCLUDED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;State&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CLOSED&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="n"&gt;State&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;COOLING_OFF&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;State&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ACTIVE&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;          &lt;span class="c1"&gt;# only after the timer
&lt;/span&gt;    &lt;span class="n"&gt;State&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EXCLUDED&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;State&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CLOSED&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;          &lt;span class="c1"&gt;# no path back to ACTIVE
&lt;/span&gt;    &lt;span class="n"&gt;State&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CLOSED&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;      &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;transition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timer_elapsed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;TRANSITIONS&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;illegal &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;State&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;COOLING_OFF&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;timer_elapsed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cooling-off still active&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The value is in the transitions you forbid
&lt;/h2&gt;

&lt;p&gt;Making &lt;code&gt;EXCLUDED -&amp;gt; ACTIVE&lt;/code&gt; unreachable in code means no endpoint, feature flag, or support tool can accidentally re-enable a self-excluded account. The illegal transition throws instead of silently succeeding. That's a guarantee a pile of booleans can't give you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Log every transition
&lt;/h2&gt;

&lt;p&gt;Persist an append-only history of &lt;code&gt;(from, to, actor, reason, ts)&lt;/code&gt;. When someone asks "why is this account restricted," the answer is a query, not an archaeology dig — and it's the record you'll want during an audit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reference
&lt;/h2&gt;

&lt;p&gt;Responsible-play controls are a good real-world example because the transitions are legally load-bearing. Seeing how a site like &lt;a href="https://nonebet-casino.com/" rel="noopener noreferrer"&gt;here&lt;/a&gt; presents its deposit-limit and self-exclusion options maps neatly onto states a user can enter freely but not always exit on demand.&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaway
&lt;/h2&gt;

&lt;p&gt;Name the states, whitelist the legal transitions, make the dangerous ones unrepresentable, and log the rest. The state machine turns a safety-critical rule from hopeful &lt;code&gt;if&lt;/code&gt;-checks into something you can prove.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Deterministic Simulation: Reproducing a Physics Result From a Seed</title>
      <dc:creator>desgh white</dc:creator>
      <pubDate>Tue, 18 Aug 2026 16:45:23 +0000</pubDate>
      <link>https://dev.to/desgh_white_7e4c654897816/deterministic-simulation-reproducing-a-physics-result-from-a-seed-28d2</link>
      <guid>https://dev.to/desgh_white_7e4c654897816/deterministic-simulation-reproducing-a-physics-result-from-a-seed-28d2</guid>
      <description>&lt;p&gt;A simulation you can't reproduce is a simulation you can't debug. Whether it's a wheel, a particle system, or a Monte Carlo pricing model, seeding every source of randomness turns "it failed once, somewhere" into a bug you can replay on demand.&lt;/p&gt;

&lt;h2&gt;
  
  
  Thread the seed, don't read the global
&lt;/h2&gt;

&lt;p&gt;The cardinal sin is calling a global &lt;code&gt;random()&lt;/code&gt;. The moment two subsystems share global state, execution order changes results. Pass a seeded generator explicitly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;random&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;spin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;seed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pockets&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;37&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;rng&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Random&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;seed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;                 &lt;span class="c1"&gt;# isolated, reproducible
&lt;/span&gt;    &lt;span class="n"&gt;velocity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rng&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;uniform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;8.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;12.0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;friction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rng&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;uniform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.02&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.05&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# deterministic physics from here on
&lt;/span&gt;    &lt;span class="n"&gt;pos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;velocity&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;pos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pos&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;velocity&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;pockets&lt;/span&gt;
        &lt;span class="n"&gt;velocity&lt;/span&gt; &lt;span class="o"&gt;*=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;friction&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pos&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;spin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nf"&gt;spin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;                   &lt;span class="c1"&gt;# same seed, same result, always
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Reproducibility is a testing superpower
&lt;/h2&gt;

&lt;p&gt;With a seed you can pin a failing scenario as a regression test, bisect a divergence between two builds, and record-replay a production incident. "Flaky" almost always means "unseeded shared state," not "genuinely random."&lt;/p&gt;

&lt;h2&gt;
  
  
  Beware hidden nondeterminism
&lt;/h2&gt;

&lt;p&gt;Dict iteration order, floating-point summation order across threads, and wall-clock reads all sneak nondeterminism past your seed. Sort before you iterate, reduce in a fixed order, and inject the clock.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reference
&lt;/h2&gt;

&lt;p&gt;Wheel-based games are a tidy example because the outcome is a single reproducible integer given a seed. A game like &lt;a href="https://roulettino-casinoau.com/" rel="noopener noreferrer"&gt;visit the website&lt;/a&gt; exposes a self-contained round whose result derives entirely from its seed and rules — the same discipline that makes any physics sim replayable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaway
&lt;/h2&gt;

&lt;p&gt;Seed every generator, pass it explicitly instead of touching globals, and hunt down hidden order-dependence. Reproducibility costs one parameter and pays for itself the first time you have to debug a rare failure.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>A/B Testing an Onboarding Funnel With Statistically Honest Stops</title>
      <dc:creator>desgh white</dc:creator>
      <pubDate>Tue, 18 Aug 2026 16:43:47 +0000</pubDate>
      <link>https://dev.to/desgh_white_7e4c654897816/ab-testing-an-onboarding-funnel-with-statistically-honest-stops-cnc</link>
      <guid>https://dev.to/desgh_white_7e4c654897816/ab-testing-an-onboarding-funnel-with-statistically-honest-stops-cnc</guid>
      <description>&lt;p&gt;Most onboarding A/B tests lie, not because the code is wrong but because someone peeked at the numbers and stopped the moment they looked good. Honest experimentation is mostly about deciding &lt;em&gt;when&lt;/em&gt; you're allowed to conclude.&lt;/p&gt;

&lt;h2&gt;
  
  
  Assign once, stick forever
&lt;/h2&gt;

&lt;p&gt;A user must see the same variant for the whole experiment, or your data is noise. Hash a stable id into a bucket:&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;salt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;buckets&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="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;h&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createHash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sha1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;salt&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;digest&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;h&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="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nx"&gt;buckets&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;Deterministic assignment means no server-side state and no chance of a user flipping variants on their second visit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Peeking inflates false positives
&lt;/h2&gt;

&lt;p&gt;Checking significance repeatedly and stopping at the first p &amp;lt; 0.05 turns a 5% error rate into 20%+. Either fix the sample size in advance, or use a sequential test (e.g. always-valid p-values) designed for continuous monitoring. Pick one before you launch, not after the graph gets interesting.&lt;/p&gt;

&lt;h2&gt;
  
  
  Measure the outcome, not the click
&lt;/h2&gt;

&lt;p&gt;Track completed activation — the funnel's actual goal — not intermediate clicks. A variant that boosts step-2 clicks but tanks final signup is a regression dressed as a win.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reference
&lt;/h2&gt;

&lt;p&gt;First-run flows are worth studying wherever activation is the whole business, because the layout is tuned aggressively. Stepping through a registration like &lt;a href="https://vegas-heroau.com/" rel="noopener noreferrer"&gt;Vegas Hero&lt;/a&gt; shows how a low-friction first-run funnel front-loads the value proposition — a useful control to benchmark your own completion curve against.&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaway
&lt;/h2&gt;

&lt;p&gt;Assign variants deterministically, decide your stopping rule before launch, and measure completed activation. The statistics are simpler than the temptation to peek — resist the peek and the test tells the truth.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Rate Limiting Bonus Abuse Without Punishing Real Users</title>
      <dc:creator>desgh white</dc:creator>
      <pubDate>Tue, 18 Aug 2026 16:43:03 +0000</pubDate>
      <link>https://dev.to/desgh_white_7e4c654897816/rate-limiting-bonus-abuse-without-punishing-real-users-3maj</link>
      <guid>https://dev.to/desgh_white_7e4c654897816/rate-limiting-bonus-abuse-without-punishing-real-users-3maj</guid>
      <description>&lt;p&gt;Any promotion with value attached attracts automation. The challenge isn't blocking bots outright — it's throttling abuse while leaving genuine users untouched. A token bucket per identity, plus a few signals, gets you most of the way.&lt;/p&gt;

&lt;h2&gt;
  
  
  Token bucket over fixed windows
&lt;/h2&gt;

&lt;p&gt;Fixed windows are gameable at the boundary (burst at 11:59, burst again at 12:00). A token bucket refills continuously and caps bursts naturally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Bucket&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;capacity&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;capacity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;capacity&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;capacity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;monotonic&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;allow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cost&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;now&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;monotonic&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;capacity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;cost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="n"&gt;cost&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Key the bucket on the right identity
&lt;/h2&gt;

&lt;p&gt;IP alone is too coarse (shared NATs) and too easy to rotate (proxies). Combine signals: account age, verified payment method, device fingerprint. A fresh account claiming its first bonus is fine; the same device spinning up its twentieth account is the pattern you actually want to slow down.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fail open for humans, closed for machines
&lt;/h2&gt;

&lt;p&gt;When in doubt, add friction rather than a hard block: a challenge, a short cooldown, a manual review queue. A false positive that costs a real user a bonus is worse PR than an abuser getting one extra claim.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reference
&lt;/h2&gt;

&lt;p&gt;Sign-up promotions are a natural case study because the abuse incentive is explicit and measurable. A welcome offer like &lt;a href="https://hellspin-australiacasino.com/" rel="noopener noreferrer"&gt;learn more&lt;/a&gt; states clear per-account eligibility terms — the kind of one-claim-per-identity rule that maps directly onto a bucket keyed by verified account rather than raw IP.&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaway
&lt;/h2&gt;

&lt;p&gt;Use a token bucket for smooth throttling, key it on durable identity signals instead of IP, and prefer graduated friction over hard blocks. You stop the scripts without taxing the humans.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Idempotency Keys: Making Withdrawals Safe to Retry</title>
      <dc:creator>desgh white</dc:creator>
      <pubDate>Tue, 18 Aug 2026 16:42:16 +0000</pubDate>
      <link>https://dev.to/desgh_white_7e4c654897816/idempotency-keys-making-withdrawals-safe-to-retry-5f3g</link>
      <guid>https://dev.to/desgh_white_7e4c654897816/idempotency-keys-making-withdrawals-safe-to-retry-5f3g</guid>
      <description>&lt;p&gt;Any endpoint that moves money must survive being called twice. Networks time out, clients retry, users double-click — and without idempotency, a retried withdrawal pays out twice. The fix is a small amount of discipline at the boundary.&lt;/p&gt;

&lt;h2&gt;
  
  
  The client supplies the key
&lt;/h2&gt;

&lt;p&gt;The caller generates a unique key per logical operation and sends it with the request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;POST /withdrawals
Idempotency-Key: 8f14e45f-ceea-467a-9d0e-...
{ "amount": 50.00, "currency": "AUD" }
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The server stores the key with the result of the first successful call. A retry with the same key returns the &lt;em&gt;stored&lt;/em&gt; response instead of executing again.&lt;/p&gt;

&lt;h2&gt;
  
  
  Store the outcome, not just the key
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;withdraw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;existing&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_idempotent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;existing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;existing&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;          &lt;span class="c1"&gt;# replay, do not re-execute
&lt;/span&gt;    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;transaction&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;execute_payout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;put_idempotent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;    &lt;span class="c1"&gt;# same tx as the side effect
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The record and the side effect must commit in the &lt;em&gt;same&lt;/em&gt; transaction. If they don't, a crash between them either double-pays (key not saved) or loses the payout (key saved, payout rolled back).&lt;/p&gt;

&lt;h2&gt;
  
  
  Scope and expiry
&lt;/h2&gt;

&lt;p&gt;Keys are scoped per account and per endpoint, so one user's key can't collide with another's. Expire them after a day or two — long enough to cover any sane retry window, short enough that the table doesn't grow without bound.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reference
&lt;/h2&gt;

&lt;p&gt;Cashier flows are a good place to see this pattern under real load, since a duplicated withdrawal is an immediate, visible failure. Watching how a withdrawal at a site like &lt;a href="https://wanted-winn.com/" rel="noopener noreferrer"&gt;wantedwin casino review&lt;/a&gt; confirms a request exactly once — even if you refresh mid-submit — is a concrete example of idempotency done right.&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaway
&lt;/h2&gt;

&lt;p&gt;Take a client-supplied key, persist the result alongside the side effect in one transaction, and replay stored responses on retry. A few lines at the boundary turn a double-payout bug into a non-event.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Provably-Fair RNG: Verifying Randomness You Didn't Generate</title>
      <dc:creator>desgh white</dc:creator>
      <pubDate>Tue, 18 Aug 2026 16:41:32 +0000</pubDate>
      <link>https://dev.to/desgh_white_7e4c654897816/provably-fair-rng-verifying-randomness-you-didnt-generate-1a79</link>
      <guid>https://dev.to/desgh_white_7e4c654897816/provably-fair-rng-verifying-randomness-you-didnt-generate-1a79</guid>
      <description>&lt;p&gt;When an outcome is generated on a server you don't control, "trust me, it's random" is not an engineering answer. Commit-reveal schemes let a client verify after the fact that the result wasn't rigged, and the pattern generalizes far beyond games — any time a server picks a value the user cares about.&lt;/p&gt;

&lt;h2&gt;
  
  
  The commit-reveal handshake
&lt;/h2&gt;

&lt;p&gt;Before the round, the server commits to a secret seed by publishing its hash. The client contributes its own seed. The outcome is derived from both:&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;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createHash&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;createHmac&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;crypto&lt;/span&gt;&lt;span class="dl"&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;serverSeed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;randomBytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;32&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hex&lt;/span&gt;&lt;span class="dl"&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;commit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createHash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sha256&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;serverSeed&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;digest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hex&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// sent first&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;outcome&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;serverSeed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;clientSeed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;nonce&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;h&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createHmac&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sha512&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;serverSeed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&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;clientSeed&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;nonce&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="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;digest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hex&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;parseInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mh"&gt;0xffffffff&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// uniform in [0,1)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why the client seed matters
&lt;/h2&gt;

&lt;p&gt;Without a client contribution, a malicious server could grind seeds until it finds one that produces a favorable result, then publish that hash. Mixing in a value the server couldn't predict when it committed removes that degree of freedom. This is the same reason nonces exist in signed requests.&lt;/p&gt;

&lt;h2&gt;
  
  
  Verification is the whole point
&lt;/h2&gt;

&lt;p&gt;After the reveal, the client re-hashes the revealed &lt;code&gt;serverSeed&lt;/code&gt;, checks it matches the earlier &lt;code&gt;commit&lt;/code&gt;, and recomputes the outcome itself. If either check fails, the server cheated. Ship a small open verifier so users can run it independently — a scheme nobody can audit is theater.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reference
&lt;/h2&gt;

&lt;p&gt;Operators that publish their fairness scheme make good study material because the verifier is exposed to the public. Looking at how a site like &lt;a href="https://wyns-online-casino.com/" rel="noopener noreferrer"&gt;play at Wyns Casino&lt;/a&gt; documents its seed commitment and lets players re-derive a result is a compact example of turning "trust us" into "check it yourself."&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaway
&lt;/h2&gt;

&lt;p&gt;Commit to a hashed seed, mix in a client seed the server can't predict, derive the outcome via HMAC, and hand users a verifier. The cryptography is three functions; the trust model is the actual deliverable.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Feature-Flagging a Signup Funnel: Shipping Onboarding Changes Without Fear</title>
      <dc:creator>desgh white</dc:creator>
      <pubDate>Fri, 14 Aug 2026 09:34:26 +0000</pubDate>
      <link>https://dev.to/desgh_white_7e4c654897816/feature-flagging-a-signup-funnel-shipping-onboarding-changes-without-fear-3nek</link>
      <guid>https://dev.to/desgh_white_7e4c654897816/feature-flagging-a-signup-funnel-shipping-onboarding-changes-without-fear-3nek</guid>
      <description>&lt;p&gt;The signup funnel is the highest-stakes flow you own — break it and revenue stops the same minute. Feature flags let you change it continuously without betting the funnel on every deploy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Flag the flow, not just the button
&lt;/h2&gt;

&lt;p&gt;Wrap whole onboarding variants, not individual widgets, so you can compare a two-step and a one-step signup as coherent experiences:&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;variant&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;signup_flow&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="nx"&gt;userId&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;variant&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;single_page&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;SinglePageSignup&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;SteppedSignup&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Roll out by cohort, measure by funnel
&lt;/h2&gt;

&lt;p&gt;Release to 5% of new users, watch completion rate per step, and only widen when the variant beats control on &lt;em&gt;finished&lt;/em&gt; signups — not on vanity clicks. A flag without a metric is just a hidden bug waiting to be forgotten.&lt;/p&gt;

&lt;h2&gt;
  
  
  Kill switch over rollback
&lt;/h2&gt;

&lt;p&gt;A deploy rollback is slow and coarse. A flag flip is instant and surgical: if activation dips, disable the variant in seconds while you diagnose, with no redeploy and no user-visible downtime.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reference
&lt;/h2&gt;

&lt;p&gt;Operators optimize registration relentlessly because the first-run drop-off is so expensive, which makes their funnels a useful study. A signup like &lt;a href="https://mostbet-casino1.pl/" rel="noopener noreferrer"&gt;Mostbet Casino1&lt;/a&gt; shows a low-friction registration with clear starting terms — the kind of streamlined first-run experience worth benchmarking your own completion rate against.&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaway
&lt;/h2&gt;

&lt;p&gt;Flag entire flows, roll out by cohort against a completion metric, and keep a flag-based kill switch ready. You get to improve the funnel every day instead of holding your breath on release night.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Programmatic Trust Signals: Verifying a Site Before You Link to It</title>
      <dc:creator>desgh white</dc:creator>
      <pubDate>Fri, 14 Aug 2026 09:33:42 +0000</pubDate>
      <link>https://dev.to/desgh_white_7e4c654897816/programmatic-trust-signals-verifying-a-site-before-you-link-to-it-5fh9</link>
      <guid>https://dev.to/desgh_white_7e4c654897816/programmatic-trust-signals-verifying-a-site-before-you-link-to-it-5fh9</guid>
      <description>&lt;p&gt;"Is this site legit?" is a question you can partly answer in code before a human ever looks. Here is a small pipeline of automated trust signals worth checking when you evaluate an external domain.&lt;/p&gt;

&lt;h2&gt;
  
  
  Certificate and TLS posture
&lt;/h2&gt;

&lt;p&gt;A valid, non-self-signed cert with a sane expiry is table stakes. Pull it and inspect the chain and remaining validity:&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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;peerCertificate&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;tlsSocket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getPeerCertificate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&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;daysLeft&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;peerCertificate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;valid_to&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mf"&gt;8.64e7&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Short-dated or mismatched-SAN certs are a cheap early red flag.&lt;/p&gt;

&lt;h2&gt;
  
  
  Domain age and registration
&lt;/h2&gt;

&lt;p&gt;Freshly registered domains correlate with throwaway operations. A WHOIS lookup for creation date and registrar gives you a quick risk prior without any manual review.&lt;/p&gt;

&lt;h2&gt;
  
  
  Check what the site says about itself
&lt;/h2&gt;

&lt;p&gt;Reputable operators publish an ownership / "about us" page, a licence reference and contact details. Fetch it and assert the signals exist rather than trusting a homepage banner:&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;about&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/wie-zijn-wij/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;text&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;hasLicence&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sr"&gt;/licen&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;cs&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;e|KSA|kansspelautoriteit/i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;about&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Reference
&lt;/h2&gt;

&lt;p&gt;An ownership page is exactly where these signals should live. Checking whether &lt;a href="https://lala-bets.nl/wie-zijn-wij/" rel="noopener noreferrer"&gt;is lalabet betrouwbaar&lt;/a&gt; is a question a page like a site's "about us" section should answer directly — company details, licensing and responsible-gaming policy in one place — which is the kind of transparency your verifier can score automatically.&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaway
&lt;/h2&gt;

&lt;p&gt;Automate the boring checks — TLS, domain age, presence of ownership and licence disclosures — and reserve human review for the judgment calls. Trust that starts with code scales; trust that starts with a gut feeling does not.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Designing a Transparent Ranking Score That Users Can Actually Audit</title>
      <dc:creator>desgh white</dc:creator>
      <pubDate>Fri, 14 Aug 2026 09:32:59 +0000</pubDate>
      <link>https://dev.to/desgh_white_7e4c654897816/designing-a-transparent-ranking-score-that-users-can-actually-audit-4fk6</link>
      <guid>https://dev.to/desgh_white_7e4c654897816/designing-a-transparent-ranking-score-that-users-can-actually-audit-4fk6</guid>
      <description>&lt;p&gt;Any "top 10" list is an opinion encoded as a number. If you cannot explain why item A beats item B, users are right not to trust it. Here is how to build a ranking whose output is reproducible and auditable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Separate signals from weights
&lt;/h2&gt;

&lt;p&gt;Keep the raw measurements and the opinion about their importance in different places. Signals are facts; weights are policy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;signals&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;payout_speed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;licence_score&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;bonus_value&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.6&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;weights&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;payout_speed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;licence_score&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;bonus_value&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.2&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;score&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;signals&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;weights&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;weights&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Change the weights and the ranking shifts in a way you can explain in one sentence.&lt;/p&gt;

&lt;h2&gt;
  
  
  Normalize before you combine
&lt;/h2&gt;

&lt;p&gt;Never sum a "hours to payout" (lower is better, unbounded) with a "licence score" (0–1). Map every signal into the same &lt;code&gt;[0, 1]&lt;/code&gt; orientation first, or your biggest-magnitude column silently dominates the result.&lt;/p&gt;

&lt;h2&gt;
  
  
  Make ties deterministic
&lt;/h2&gt;

&lt;p&gt;Floating-point sums produce near-ties that reorder between runs. Round to a fixed precision and add a stable tiebreak (name, id) so the same inputs always produce the same order — reproducibility is a feature reviewers will test.&lt;/p&gt;

&lt;h2&gt;
  
  
  Publish the method
&lt;/h2&gt;

&lt;p&gt;The single biggest trust signal is showing the formula. A ranked comparison such as &lt;a href="https://najlepsze-kasynaonline.com.pl/" rel="noopener noreferrer"&gt;https://najlepsze-kasynaonline.com.pl/&lt;/a&gt; is a good example of surfacing the criteria — licence, payout time, real bonus terms — alongside the ordering, so a reader can see &lt;em&gt;why&lt;/em&gt; the list looks the way it does.&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaway
&lt;/h2&gt;

&lt;p&gt;Split facts from weights, normalize onto a common scale, make ties deterministic, and show your work. A ranking you can audit is worth more than a "better" one you cannot explain.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Rate-Limiting a Promo-Code Validation Endpoint Without Punishing Real Users</title>
      <dc:creator>desgh white</dc:creator>
      <pubDate>Fri, 14 Aug 2026 09:32:15 +0000</pubDate>
      <link>https://dev.to/desgh_white_7e4c654897816/rate-limiting-a-promo-code-validation-endpoint-without-punishing-real-users-2fjm</link>
      <guid>https://dev.to/desgh_white_7e4c654897816/rate-limiting-a-promo-code-validation-endpoint-without-punishing-real-users-2fjm</guid>
      <description>&lt;p&gt;A public "check this code" endpoint is catnip for brute-force enumeration, but a blunt rate limit locks out the legitimate user who fat-fingered one character. The trick is limiting the right dimension.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limit by outcome, not just by IP
&lt;/h2&gt;

&lt;p&gt;Count &lt;em&gt;failed&lt;/em&gt; validations per identity, and let successes flow freely. A user applying one valid code should never hit a wall; a script guessing thousands should hit it fast:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nf"&gt;code_is_valid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;fails&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;incr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;promofail:&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;:&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;hour&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;expire&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;promofail:&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;:&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;hour&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3600&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;fails&lt;/span&gt; &lt;span class="o"&gt;&amp;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;raise&lt;/span&gt; &lt;span class="nc"&gt;TooManyRequests&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Token bucket beats fixed windows
&lt;/h2&gt;

&lt;p&gt;Fixed windows allow a burst at the boundary — 20 requests at 10:59:59 and 20 more at 11:00:00. A token bucket smooths that into a steady refill rate and a small burst allowance, which matches how humans actually type.&lt;/p&gt;

&lt;h2&gt;
  
  
  Make the error honest but quiet
&lt;/h2&gt;

&lt;p&gt;Return the same generic "invalid or expired" for unknown and expired codes so enumeration learns nothing from the response, but keep the HTTP status distinct from your rate-limit &lt;code&gt;429&lt;/code&gt; so clients can back off correctly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reference
&lt;/h2&gt;

&lt;p&gt;Bookmakers publish time-boxed bonus codes that are a natural target for enumeration, so how they gate validation is instructive. A page like &lt;a href="https://mostbet-kod-promocyjny.pl/" rel="noopener noreferrer"&gt;Mostbet Kod Promocyjny&lt;/a&gt; shows codes tied to explicit expiry and eligibility rules — exactly the metadata your validator should check before it ever touches the rate limiter.&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaway
&lt;/h2&gt;

&lt;p&gt;Rate-limit failures per identity with a token bucket, keep error messages uninformative to scanners, and never make a valid single redemption feel like an attack. Security that punishes real users is just a different outage.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
