Created
March 27, 2026 11:20
-
-
Save orius123/abeceef70eed7167a55e0ded1b9ed749 to your computer and use it in GitHub Desktop.
Replay Protection - PROD Rollout Plan (March 2026)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!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 — 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> — only 0.4% of requests are rejected (confirmed attacks). | |
| </p> | |
| <div class="attack-callout"> | |
| <strong>Active attack on Elementor</strong> — 265K requests blocked in 7 days. Attacker using 5+ IPs across 3 continents, | |
| hitting every 2–3 seconds. They've scaled from 1 IP (March 24) to 5+ rotating IPs. | |
| Block mode is holding — every request rejected. | |
| </div> | |
| </div> | |
| <!-- The Problem --> | |
| <div class="section"> | |
| <div class="section-label">Risk Assessment</div> | |
| <h2>What Happens If We Switch Log → 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 → 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% — 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% — 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% — 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% — 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 → Log. These companies already have the Block FF enabled — 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_<projectID>: "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_<projectID>: "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–2%<br><small style="color:var(--text-dim)">verified modern SDK</small></td> | |
| <td>Verified: 0% empty nonce</td> | |
| <td><code>BLOCK_<pid>: 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_<pid>: 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: <5% empty nonce | |
| <small>Enable with DD monitoring</small> | |
| </div> | |
| <div class="bucket red"> | |
| Red: >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 → | |
| <strong>Step 1:</strong> Remove license flags → | |
| <strong>Step 2:</strong> Enable Block for Green companies → | |
| <strong>Step 2.5:</strong> Reach out to Yellow/Red companies about SDK upgrade → | |
| <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