Skip to content

Instantly share code, notes, and snippets.

@orius123
Created March 27, 2026 11:20
Show Gist options
  • Select an option

  • Save orius123/abeceef70eed7167a55e0ded1b9ed749 to your computer and use it in GitHub Desktop.

Select an option

Save orius123/abeceef70eed7167a55e0ded1b9ed749 to your computer and use it in GitHub Desktop.
Replay Protection - PROD Rollout Plan (March 2026)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Replay Protection — PROD Rollout Plan</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;600;700&family=Fira+Code:wght@400;500;600&display=swap" rel="stylesheet">
<style>
:root {
--font-body: 'DM Sans', system-ui, sans-serif;
--font-mono: 'Fira Code', 'SF Mono', Consolas, monospace;
--bg: #f7f8fc;
--surface: #ffffff;
--surface2: #f0f2f8;
--surface-elevated: #ffffff;
--border: rgba(0, 0, 0, 0.07);
--border-bright: rgba(0, 0, 0, 0.14);
--text: #1a1d2e;
--text-dim: #6b7185;
--accent: #1e3a5f;
--accent-light: #2d5a8e;
--accent-dim: rgba(30, 58, 95, 0.06);
--gold: #d4a73a;
--gold-dim: rgba(212, 167, 58, 0.10);
--green: #0f8a4f;
--green-dim: rgba(15, 138, 79, 0.08);
--green-bg: rgba(15, 138, 79, 0.12);
--yellow: #b8860b;
--yellow-dim: rgba(184, 134, 11, 0.08);
--yellow-bg: rgba(184, 134, 11, 0.12);
--red: #c0392b;
--red-dim: rgba(192, 57, 43, 0.08);
--red-bg: rgba(192, 57, 43, 0.12);
--blue: #2563eb;
--blue-dim: rgba(37, 99, 235, 0.08);
}
@media (prefers-color-scheme: dark) {
:root {
--bg: #0f1219;
--surface: #181d28;
--surface2: #1e2433;
--surface-elevated: #222939;
--border: rgba(255, 255, 255, 0.06);
--border-bright: rgba(255, 255, 255, 0.12);
--text: #e2e5f0;
--text-dim: #8890a8;
--accent: #6ba3d6;
--accent-light: #8ec0e8;
--accent-dim: rgba(107, 163, 214, 0.10);
--gold: #e8c45a;
--gold-dim: rgba(232, 196, 90, 0.10);
--green: #34d399;
--green-dim: rgba(52, 211, 153, 0.10);
--green-bg: rgba(52, 211, 153, 0.14);
--yellow: #fbbf24;
--yellow-dim: rgba(251, 191, 36, 0.10);
--yellow-bg: rgba(251, 191, 36, 0.14);
--red: #f87171;
--red-dim: rgba(248, 113, 113, 0.10);
--red-bg: rgba(248, 113, 113, 0.14);
--blue: #60a5fa;
--blue-dim: rgba(96, 165, 250, 0.10);
}
}
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
body {
font-family: var(--font-body);
background: var(--bg);
background-image: radial-gradient(ellipse at 50% 0%, var(--accent-dim) 0%, transparent 50%);
color: var(--text);
line-height: 1.6;
padding: 2rem 1rem 4rem;
}
.container { max-width: 1100px; margin: 0 auto; }
/* Header */
.header {
text-align: center;
margin-bottom: 3rem;
animation: fadeUp 0.6s ease both;
}
.header-label {
font-family: var(--font-mono);
font-size: 0.75rem;
font-weight: 500;
letter-spacing: 0.08em;
text-transform: uppercase;
color: var(--gold);
margin-bottom: 0.5rem;
}
.header h1 {
font-size: 2rem;
font-weight: 700;
color: var(--accent);
margin-bottom: 0.5rem;
}
.header-date {
font-size: 0.9rem;
color: var(--text-dim);
}
/* KPI row */
.kpi-row {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 1rem;
margin-bottom: 2.5rem;
}
.kpi {
background: var(--surface);
border: 1px solid var(--border);
border-radius: 12px;
padding: 1.25rem 1.5rem;
text-align: center;
animation: fadeScale 0.5s ease both;
}
.kpi:nth-child(1) { animation-delay: 0.1s; }
.kpi:nth-child(2) { animation-delay: 0.15s; }
.kpi:nth-child(3) { animation-delay: 0.2s; }
.kpi:nth-child(4) { animation-delay: 0.25s; }
.kpi-value {
font-size: 1.8rem;
font-weight: 700;
font-family: var(--font-mono);
color: var(--accent);
line-height: 1.2;
}
.kpi-value.green { color: var(--green); }
.kpi-value.red { color: var(--red); }
.kpi-value.gold { color: var(--gold); }
.kpi-label {
font-size: 0.8rem;
color: var(--text-dim);
margin-top: 0.25rem;
}
/* Section */
.section {
background: var(--surface);
border: 1px solid var(--border);
border-radius: 12px;
padding: 2rem;
margin-bottom: 1.5rem;
animation: fadeUp 0.5s ease both;
}
.section:nth-of-type(2) { animation-delay: 0.1s; }
.section:nth-of-type(3) { animation-delay: 0.15s; }
.section:nth-of-type(4) { animation-delay: 0.2s; }
.section:nth-of-type(5) { animation-delay: 0.25s; }
.section:nth-of-type(6) { animation-delay: 0.3s; }
.section-label {
font-family: var(--font-mono);
font-size: 0.7rem;
font-weight: 600;
letter-spacing: 0.06em;
text-transform: uppercase;
color: var(--gold);
margin-bottom: 0.5rem;
display: flex;
align-items: center;
gap: 0.5rem;
}
.section-label::before {
content: '';
width: 8px; height: 8px;
border-radius: 50%;
background: var(--gold);
flex-shrink: 0;
}
.section h2 {
font-size: 1.35rem;
font-weight: 700;
color: var(--text);
margin-bottom: 1rem;
}
.section h3 {
font-size: 1.05rem;
font-weight: 600;
color: var(--text);
margin: 1.25rem 0 0.75rem;
}
/* Traffic split bar */
.traffic-bar-container { margin: 1.25rem 0; }
.traffic-bar {
display: flex;
height: 36px;
border-radius: 8px;
overflow: hidden;
border: 1px solid var(--border);
}
.traffic-bar .segment {
display: flex;
align-items: center;
justify-content: center;
font-family: var(--font-mono);
font-size: 0.75rem;
font-weight: 600;
color: #fff;
transition: flex-basis 0.6s ease;
}
.segment.block-seg { background: var(--green); flex-basis: 61%; }
.segment.log-seg { background: var(--yellow); flex-basis: 39%; }
.traffic-legend {
display: flex;
gap: 1.5rem;
margin-top: 0.75rem;
font-size: 0.85rem;
}
.legend-item {
display: flex;
align-items: center;
gap: 0.4rem;
}
.legend-dot {
width: 10px; height: 10px;
border-radius: 3px;
flex-shrink: 0;
}
.legend-dot.block { background: var(--green); }
.legend-dot.log { background: var(--yellow); }
.legend-value {
font-family: var(--font-mono);
font-weight: 600;
font-size: 0.8rem;
}
/* Attack callout */
.attack-callout {
background: var(--red-dim);
border: 1px solid var(--red);
border-left: 4px solid var(--red);
border-radius: 8px;
padding: 1rem 1.25rem;
margin: 1rem 0;
font-size: 0.9rem;
}
.attack-callout strong { color: var(--red); }
/* Problem highlight */
.problem-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1rem;
margin: 1rem 0;
}
@media (max-width: 640px) { .problem-grid { grid-template-columns: 1fr; } }
.problem-card {
border-radius: 8px;
padding: 1rem 1.25rem;
border: 1px solid var(--border);
}
.problem-card.safe { background: var(--green-dim); border-color: var(--green); }
.problem-card.danger { background: var(--red-dim); border-color: var(--red); }
.problem-card.warn { background: var(--yellow-dim); border-color: var(--yellow); }
.problem-card.info { background: var(--blue-dim); border-color: var(--blue); }
.problem-card .pc-value {
font-family: var(--font-mono);
font-size: 1.4rem;
font-weight: 700;
line-height: 1.2;
}
.problem-card.safe .pc-value { color: var(--green); }
.problem-card.danger .pc-value { color: var(--red); }
.problem-card.warn .pc-value { color: var(--yellow); }
.problem-card.info .pc-value { color: var(--blue); }
.problem-card .pc-label {
font-size: 0.8rem;
color: var(--text-dim);
margin-top: 0.15rem;
}
.problem-card .pc-desc {
font-size: 0.8rem;
color: var(--text);
margin-top: 0.5rem;
line-height: 1.4;
}
/* Comparison bar */
.compare-bars { margin: 1.25rem 0; }
.compare-row {
display: flex;
align-items: center;
gap: 0.75rem;
margin-bottom: 0.75rem;
}
.compare-label {
font-size: 0.85rem;
font-weight: 600;
width: 140px;
flex-shrink: 0;
text-align: right;
}
.compare-track {
flex: 1;
height: 28px;
background: var(--surface2);
border-radius: 6px;
position: relative;
overflow: hidden;
}
.compare-fill {
height: 100%;
border-radius: 6px;
display: flex;
align-items: center;
padding-left: 0.75rem;
font-family: var(--font-mono);
font-size: 0.75rem;
font-weight: 600;
color: #fff;
transition: width 0.8s ease;
}
.compare-fill.good { background: var(--green); }
.compare-fill.bad { background: var(--red); }
/* Steps */
.steps { margin: 1rem 0; }
.step {
display: grid;
grid-template-columns: 48px 1fr;
gap: 0 1rem;
margin-bottom: 1.5rem;
position: relative;
}
.step::before {
content: '';
position: absolute;
left: 23px;
top: 48px;
bottom: -1.5rem;
width: 2px;
background: var(--border-bright);
}
.step:last-child::before { display: none; }
.step-num {
width: 48px; height: 48px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-family: var(--font-mono);
font-size: 1.1rem;
font-weight: 700;
color: #fff;
grid-row: 1 / 3;
}
.step-num.low { background: var(--green); }
.step-num.medium { background: var(--yellow); }
.step-num.high { background: var(--red); }
.step-title {
font-size: 1.05rem;
font-weight: 700;
align-self: end;
padding-bottom: 0.15rem;
}
.step-body {
grid-column: 2;
padding-top: 0.25rem;
}
.step-body p {
font-size: 0.9rem;
color: var(--text-dim);
margin-bottom: 0.5rem;
line-height: 1.5;
}
.step-meta {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
margin-top: 0.5rem;
}
.badge {
font-family: var(--font-mono);
font-size: 0.7rem;
font-weight: 600;
padding: 0.2rem 0.6rem;
border-radius: 4px;
letter-spacing: 0.02em;
}
.badge.risk-low { background: var(--green-bg); color: var(--green); }
.badge.risk-med { background: var(--yellow-bg); color: var(--yellow); }
.badge.risk-high { background: var(--red-bg); color: var(--red); }
.badge.info { background: var(--accent-dim); color: var(--accent); }
/* Risk table */
.table-wrap {
overflow-x: auto;
margin: 1rem 0;
border-radius: 8px;
border: 1px solid var(--border);
}
table {
width: 100%;
border-collapse: collapse;
font-size: 0.85rem;
}
thead {
position: sticky;
top: 0;
z-index: 2;
}
thead th {
background: var(--accent);
color: #fff;
font-weight: 600;
font-size: 0.75rem;
letter-spacing: 0.03em;
text-transform: uppercase;
padding: 0.75rem 1rem;
text-align: left;
white-space: nowrap;
}
tbody td {
padding: 0.75rem 1rem;
border-top: 1px solid var(--border);
vertical-align: top;
}
tbody tr:nth-child(even) { background: var(--surface2); }
tbody tr:hover { background: var(--accent-dim); }
td code {
font-family: var(--font-mono);
font-size: 0.8em;
background: var(--surface2);
padding: 0.1em 0.35em;
border-radius: 3px;
}
td .risk-indicator {
display: inline-flex;
align-items: center;
gap: 0.35rem;
font-weight: 600;
font-size: 0.8rem;
}
td .risk-dot {
width: 8px; height: 8px;
border-radius: 50%;
flex-shrink: 0;
}
td .risk-dot.low { background: var(--green); }
td .risk-dot.med { background: var(--yellow); }
td .risk-dot.high { background: var(--red); }
/* Recommendation */
.rec-box {
background: var(--gold-dim);
border: 1px solid var(--gold);
border-left: 4px solid var(--gold);
border-radius: 8px;
padding: 1.25rem 1.5rem;
margin: 1rem 0;
}
.rec-box h4 {
color: var(--gold);
font-size: 0.95rem;
margin-bottom: 0.5rem;
}
.rec-box p, .rec-box li {
font-size: 0.9rem;
line-height: 1.5;
}
.rec-box ul {
padding-left: 1.25rem;
margin-top: 0.5rem;
}
.rec-box li { margin-bottom: 0.25rem; }
/* Bucket grid */
.bucket-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 0.75rem;
margin: 0.75rem 0;
}
@media (max-width: 640px) { .bucket-grid { grid-template-columns: 1fr; } }
.bucket {
border-radius: 8px;
padding: 0.75rem 1rem;
text-align: center;
font-size: 0.85rem;
font-weight: 600;
}
.bucket.green { background: var(--green-bg); color: var(--green); border: 1px solid var(--green); }
.bucket.yellow { background: var(--yellow-bg); color: var(--yellow); border: 1px solid var(--yellow); }
.bucket.red { background: var(--red-bg); color: var(--red); border: 1px solid var(--red); }
.bucket small {
display: block;
font-weight: 400;
font-size: 0.78rem;
margin-top: 0.25rem;
opacity: 0.85;
}
/* Bottom line */
.bottom-line {
background: var(--accent);
color: #fff;
border-radius: 12px;
padding: 1.5rem 2rem;
margin-top: 2rem;
text-align: center;
animation: fadeUp 0.5s ease 0.4s both;
}
.bottom-line h3 {
font-size: 1.1rem;
font-weight: 700;
margin-bottom: 0.5rem;
color: var(--gold);
}
.bottom-line p {
font-size: 0.95rem;
line-height: 1.5;
opacity: 0.92;
}
/* Animations */
@keyframes fadeUp {
from { opacity: 0; transform: translateY(12px); }
to { opacity: 1; transform: translateY(0); }
}
@keyframes fadeScale {
from { opacity: 0; transform: scale(0.95); }
to { opacity: 1; transform: scale(1); }
}
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after { animation: none !important; transition: none !important; }
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<div class="header-label">Security Briefing</div>
<h1>Replay Protection — PROD Rollout Plan</h1>
<div class="header-date">March 26, 2026 &mdash; Data: Datadog 7-day window</div>
</div>
<!-- KPIs -->
<div class="kpi-row">
<div class="kpi">
<div class="kpi-value">233M</div>
<div class="kpi-label">PROD flow requests / week</div>
</div>
<div class="kpi">
<div class="kpi-value green">61%</div>
<div class="kpi-label">Already in Block mode</div>
</div>
<div class="kpi">
<div class="kpi-value gold">39%</div>
<div class="kpi-label">Log-only (not blocking)</div>
</div>
<div class="kpi">
<div class="kpi-value red">265K</div>
<div class="kpi-label">Attacks blocked this week</div>
</div>
</div>
<!-- Current State -->
<div class="section">
<div class="section-label">Current State</div>
<h2>PROD Traffic Split</h2>
<div class="traffic-bar-container">
<div class="traffic-bar">
<div class="segment block-seg">61% Block</div>
<div class="segment log-seg">39% Log</div>
</div>
<div class="traffic-legend">
<div class="legend-item">
<span class="legend-dot block"></span>
<span>Block mode</span>
<span class="legend-value">142.6M / week</span>
</div>
<div class="legend-item">
<span class="legend-dot log"></span>
<span>Log-only</span>
<span class="legend-value">91M / week</span>
</div>
</div>
</div>
<p style="font-size:0.9rem; color:var(--text-dim); margin-top:0.75rem;">
9 projects have per-project Block FF enabled. Companies created after Jan 15, 2026 get Block automatically.
Block mode has a <strong style="color:var(--green);">99.6% pass rate</strong> &mdash; only 0.4% of requests are rejected (confirmed attacks).
</p>
<div class="attack-callout">
<strong>Active attack on Elementor</strong> &mdash; 265K requests blocked in 7 days. Attacker using 5+ IPs across 3 continents,
hitting every 2&ndash;3 seconds. They've scaled from 1 IP (March 24) to 5+ rotating IPs.
Block mode is holding &mdash; every request rejected.
</div>
</div>
<!-- The Problem -->
<div class="section">
<div class="section-label">Risk Assessment</div>
<h2>What Happens If We Switch Log &rarr; Block Today?</h2>
<p style="font-size:0.9rem; color:var(--text-dim); margin-bottom:1rem;">
The 91M Log-only requests have a very different risk profile than existing Block traffic.
</p>
<div class="compare-bars">
<div class="compare-row">
<span class="compare-label">Existing Block</span>
<div class="compare-track">
<div class="compare-fill good" style="width: 4%;">0.4%</div>
</div>
</div>
<div class="compare-row">
<span class="compare-label">Log &rarr; Block</span>
<div class="compare-track">
<div class="compare-fill bad" style="width: 55%;">18.4%</div>
</div>
</div>
</div>
<p style="font-size:0.8rem; color:var(--text-dim); text-align:center; margin-bottom:1rem;">
Percentage of requests that would be rejected
</p>
<div class="problem-grid">
<div class="problem-card safe">
<div class="pc-value">73.2M</div>
<div class="pc-label">80.7% &mdash; Would pass</div>
<div class="pc-desc">Modern SDKs, valid nonces. No impact.</div>
</div>
<div class="problem-card danger">
<div class="pc-value">11M</div>
<div class="pc-label">12.1% &mdash; Old SDK, empty nonce</div>
<div class="pc-desc">SDKs that don't send the nonce header. Block mode rejects them immediately. <strong>This is the #1 risk.</strong></div>
</div>
<div class="problem-card warn">
<div class="pc-value">5.7M</div>
<div class="pc-label">6.3% &mdash; Nonce validation failures</div>
<div class="pc-desc">Mostly SDK polling with expired grace periods. Some may be actual replay attempts.</div>
</div>
<div class="problem-card info">
<div class="pc-value">800K</div>
<div class="pc-label">0.9% &mdash; Nonce-exempt actions</div>
<div class="pc-desc">Magic link / enchanted link verifications. Always pass regardless of mode.</div>
</div>
</div>
</div>
<!-- Rollout Plan -->
<div class="section">
<div class="section-label">Rollout Plan</div>
<h2>3-Step Phased Rollout</h2>
<div class="steps">
<div class="step">
<div class="step-num low">1</div>
<div class="step-title">Remove <code>skipReplayAttackProtection</code> license config</div>
<div class="step-body">
<p>Remove the legacy license flag that overrides Block &rarr; Log. These companies already have the Block FF enabled &mdash; the license is the only thing holding it back.</p>
<p><strong>Affected:</strong> 1 known company (24K downgraded logs/week). Their traffic should match existing Block projects (~0.4% rejection rate).</p>
<p><strong>Rollback:</strong> Re-add the license flag via management API.</p>
<div class="step-meta">
<span class="badge risk-low">Risk: Low</span>
<span class="badge info">Immediate effect</span>
</div>
</div>
</div>
<div class="step">
<div class="step-num medium">2</div>
<div class="step-title">Enable Block for low-risk companies</div>
<div class="step-body">
<p>Enable per-project Block FF for Log-mode companies that have <strong>modern SDKs</strong> (zero empty nonces in their traffic). These will behave identically to existing Block projects.</p>
<p><strong>Prerequisite:</strong> Per-company audit of empty nonce rate (see Step 0 recommendation below).</p>
<p><strong>Rollback:</strong> Set per-project <code>BLOCK_&lt;projectID&gt;: "false"</code> in deployment repo.</p>
<div class="step-meta">
<span class="badge risk-med">Risk: Low-Medium</span>
<span class="badge info">Requires audit first</span>
</div>
</div>
</div>
<div class="step">
<div class="step-num high">3</div>
<div class="step-title">Enable Block for sensitive / high-traffic companies</div>
<div class="step-body">
<p>Enable Block for remaining companies after coordinating SDK upgrades. Without upgrade, up to <strong>18% of their traffic would be blocked</strong> (broken authentication for end users).</p>
<p><strong>Prerequisite:</strong> Customer communication + SDK upgrade + close Datadog monitoring.</p>
<p><strong>Rollback:</strong> Set per-project <code>BLOCK_&lt;projectID&gt;: "false"</code> in deployment repo.</p>
<div class="step-meta">
<span class="badge risk-high">Risk: High without SDK upgrade</span>
<span class="badge risk-low">Risk: Low after SDK upgrade</span>
</div>
</div>
</div>
</div>
</div>
<!-- Risk Matrix -->
<div class="section">
<div class="section-label">Risk Matrix</div>
<h2>Step-by-Step Risk Assessment</h2>
<div class="table-wrap">
<table>
<thead>
<tr>
<th>Step</th>
<th>Traffic Affected</th>
<th>Expected Block Rate</th>
<th>SDK Risk</th>
<th>Rollback</th>
<th>Overall</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Step 1</strong><br>License removal</td>
<td>24K logs/week<br><small style="color:var(--text-dim)">1 company</small></td>
<td>~0.4%<br><small style="color:var(--text-dim)">matches existing Block</small></td>
<td>Modern SDK expected</td>
<td>Re-add license flag</td>
<td><span class="risk-indicator"><span class="risk-dot low"></span> Low</span></td>
</tr>
<tr>
<td><strong>Step 2</strong><br>Safe companies</td>
<td>Varies per company<br><small style="color:var(--text-dim)">Green-bucket only</small></td>
<td>0&ndash;2%<br><small style="color:var(--text-dim)">verified modern SDK</small></td>
<td>Verified: 0% empty nonce</td>
<td><code>BLOCK_&lt;pid&gt;: false</code></td>
<td><span class="risk-indicator"><span class="risk-dot med"></span> Low-Med</span></td>
</tr>
<tr>
<td><strong>Step 3</strong><br>Sensitive companies</td>
<td>High volume<br><small style="color:var(--text-dim)">remaining Log pool</small></td>
<td>Up to 18%<br><small style="color:var(--red)">without SDK upgrade</small></td>
<td>Old SDKs present</td>
<td><code>BLOCK_&lt;pid&gt;: false</code></td>
<td><span class="risk-indicator"><span class="risk-dot high"></span> High*</span></td>
</tr>
</tbody>
</table>
</div>
<p style="font-size:0.8rem; color:var(--text-dim); margin-top:0.5rem;">
* High risk WITHOUT SDK upgrade. Drops to Low after customers upgrade to SDK versions that send the nonce header.
</p>
</div>
<!-- Recommendation -->
<div class="section">
<div class="section-label">Recommendation</div>
<h2>Add Step 0: Per-Company SDK Audit</h2>
<div class="rec-box">
<h4>Before Step 2, bucket all Log-mode companies by SDK health</h4>
<p>Query each company's empty nonce rate in Datadog. The empty nonce rate directly predicts the block rate when switching to Block mode.</p>
</div>
<div class="bucket-grid">
<div class="bucket green">
Green: 0% empty nonce
<small>Safe for Block immediately</small>
</div>
<div class="bucket yellow">
Yellow: &lt;5% empty nonce
<small>Enable with DD monitoring</small>
</div>
<div class="bucket red">
Red: &gt;5% empty nonce
<small>SDK upgrade required first</small>
</div>
</div>
<h3>Why this matters</h3>
<p style="font-size:0.9rem; color:var(--text-dim); line-height:1.6;">
The 18.4% failure rate in Log mode is <strong>entirely driven by old SDKs</strong> that don't send the nonce header.
Companies with modern SDKs will see the same 0.4% block rate as existing Block projects.
The audit separates the safe pool (immediate rollout) from the SDK-upgrade pool (needs customer coordination).
</p>
<h3>Rollout sequence with Step 0</h3>
<p style="font-size:0.9rem; color:var(--text-dim); line-height:1.6;">
<strong>Step 0:</strong> Run audit, bucket companies &rarr;
<strong>Step 1:</strong> Remove license flags &rarr;
<strong>Step 2:</strong> Enable Block for Green companies &rarr;
<strong>Step 2.5:</strong> Reach out to Yellow/Red companies about SDK upgrade &rarr;
<strong>Step 3:</strong> Enable Block for remaining companies after SDK upgrade confirmed.
</p>
</div>
<!-- Bottom Line -->
<div class="bottom-line">
<h3>Bottom Line</h3>
<p>
The plan is sound. The only major risk is old SDKs (11M requests/week).
Adding a per-company audit as Step 0 eliminates surprises.
Green-bucket companies can move to Block immediately with zero expected user impact.
</p>
</div>
</div>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment