Move to page bundle and isolate the simulator

This commit is contained in:
Andrew Stryker
2026-03-30 22:19:19 -07:00
parent f20c90a91c
commit 288eaa8ccb
3 changed files with 323 additions and 299 deletions
@@ -1,3 +1,3 @@
index.md
_index.md
figure/
libs/
@@ -151,12 +151,12 @@ This is the approach we will use for the rest of the analysis.
## The Evidence
Below is a chronological account of eight events from the first two months of
the administration. For each event, I describe what happened, assess the
likelihood ratio, and cite the source.
the administration. For each event, I describe what happened, give my assessment
of how the event is consistent and not consistent with an autogolpe, and
assign a likelihood ratio.
### 1. Firing Inspectors General (January 24)
{{% details summary="**1. Firing Inspectors General (January 24)** --- LR = 9" %}}
On a late Friday night, the administration [fired at least 17 independent
inspectors general][NPR-IG] across federal agencies, effective immediately.
Inspectors general are the government's internal watchdogs, charged with
@@ -174,9 +174,10 @@ make this more consistent with the autogolpe hypothesis.
\( P(E \mid A) = 0.90 \), \( P(E \mid \neg A) = 0.10 \), \( \text{LR} = 9 \).
[NPR-IG]: https://www.npr.org/2025/01/25/g-s1-44771/trump-fires-inspectors-general
{{% /details %}}
### 2. Shutting Down USAID (February 2)
{{% details summary="**2. Shutting Down USAID (February 2)** --- LR ≈ 27" %}}
The administration [placed all approximately 4,700 USAID employees on
administrative leave][WaPo-USAID] and moved to shut down the agency---a
Congressionally established agency with a statutory mandate. Approximately 92%
@@ -194,9 +195,10 @@ governance, even aggressive governance.
\( P(E \mid A) = 0.80 \), \( P(E \mid \neg A) = 0.03 \), \( \text{LR} \approx 27 \).
[WaPo-USAID]: https://www.washingtonpost.com/politics/2025/02/02/usaid-trump-musk/
{{% /details %}}
### 3. Accessing Government Computer Systems (February 4)
{{% details summary="**3. Accessing Government Computer Systems (February 4)** --- LR ≈ 5" %}}
Elon Musk's DOGE team [gained access to the Treasury Department's Bureau of
Fiscal Service payment system][NPR-Treasury], which disburses roughly $5.4
trillion annually. They also [accessed the Office of Personnel Management's
@@ -214,9 +216,11 @@ evidence in the set---it is the most amenable to an innocent explanation.
\( P(E \mid A) = 0.70 \), \( P(E \mid \neg A) = 0.15 \), \( \text{LR} \approx 5 \).
[NPR-Treasury]: https://www.npr.org/2025/02/04/nx-s1-5285403/musks-doge-group-has-access-to-the-federal-payments-system-what-does-that-mean
[WaPo-OPM]: https://www.washingtonpost.com/national-security/2025/02/06/elon-musk-doge-access-personnel-data-opm-security/
{{% /details %}}
### 4. Mass Firing Federal Workers (February 13)
{{% details summary="**4. Mass Firing Federal Workers (February 13)** --- LR = 9" %}}
The administration [fired over 24,000 probationary employees][NPR-Layoffs]
across agencies including the CDC, Department of Education, Department of
Energy, and the National Nuclear Security Administration. Many of these workers
@@ -234,9 +238,10 @@ restructuring.
\( P(E \mid A) = 0.90 \), \( P(E \mid \neg A) = 0.10 \), \( \text{LR} = 9 \).
[NPR-Layoffs]: https://www.npr.org/2025/02/13/nx-s1-5296928/layoffs-trump-doge-education-energy
{{% /details %}}
### 5. Asserting Executive Authority over Law Interpretation (February 18)
{{% details summary="**5. Asserting Executive Authority over Law Interpretation (February 18)** --- LR = 8" %}}
The president signed an executive order titled "Ensuring Accountability for All
Agencies," [declaring that the president and attorney general "shall provide
authoritative interpretations of law for the executive branch."][NPR-EO] The
@@ -254,9 +259,10 @@ is narrow, but it exists.
\( P(E \mid A) = 0.80 \), \( P(E \mid \neg A) = 0.10 \), \( \text{LR} = 8 \).
[NPR-EO]: https://www.npr.org/2025/02/19/nx-s1-5302481/trump-independent-agencies
{{% /details %}}
### 6. "Long Live the King" (February 19)
{{% details summary="**6. "Long Live the King" (February 19)** --- LR = 7" %}}
The official White House accounts on X, Instagram, and Facebook [posted an
AI-generated image][NBC-King] depicting the president wearing a bejeweled
golden crown, captioned "LONG LIVE THE KING." The White House Deputy Chief
@@ -274,9 +280,10 @@ context lends it weight that a personal social media post would not carry.
\( P(E \mid A) = 0.70 \), \( P(E \mid \neg A) = 0.10 \), \( \text{LR} = 7 \).
[NBC-King]: https://www.nbcnews.com/politics/donald-trump/king-trump-rcna192912
{{% /details %}}
### 7. Confirming Kash Patel as FBI Director (February 20)
{{% details summary="**7. Confirming Kash Patel as FBI Director (February 20)** --- LR = 17" %}}
The Senate [confirmed Kash Patel as FBI Director][NPR-Patel] on a 51--49
vote---the narrowest FBI director confirmation in history. Previous directors
received 92 or more votes. Patel authored a book listing over 60 government
@@ -293,9 +300,11 @@ beyond loyalty to something more closely resembling a plan.
\( P(E \mid A) = 0.85 \), \( P(E \mid \neg A) = 0.05 \), \( \text{LR} = 17 \).
[NPR-Patel]: https://www.npr.org/2025/02/20/g-s1-49696/trump-cabinet-picks-kash-patel
[PBS-Patel]: https://www.pbs.org/newshour/show/senators-ask-fbi-director-nominee-kash-patel-about-enemies-list-and-politicization
{{% /details %}}
### 8. Firing Military Leadership (February 21)
{{% details summary="**8. Firing Military Leadership (February 21)** --- LR = 15" %}}
As described in the worked example above, the administration [fired the
Chairman of the Joint Chiefs of Staff, the Chief of Naval Operations, the
Air Force Vice Chief of Staff, and several Judge Advocates General][PBS-Military]
@@ -305,6 +314,9 @@ simultaneous nature of these firings, however, goes well beyond that.
\( P(E \mid A) = 0.75 \), \( P(E \mid \neg A) = 0.05 \), \( \text{LR} = 15 \).
[PBS-Military]: https://www.pbs.org/newshour/politics/trump-fires-gen-cq-brown-as-chairman-of-the-joint-chiefs-of-staff
{{% /details %}}
## Analysis
@@ -432,285 +444,9 @@ bind_rows(
## Try Your Own Values
The likelihood ratios above are my assessments. You may disagree. The
simulator below lets you adjust the prior probability and each event's
likelihoods to see how your own assumptions change the conclusion. You can
also uncheck events to exclude them entirely.
<style>
#bayes-sim {
margin: 1.5em 0;
font-family: inherit;
line-height: 1.4;
}
#bayes-sim .sim-prior-ctl {
margin-bottom: 1.5em;
padding: 1em;
border: 1px solid var(--border, #ddd);
border-radius: 6px;
background: var(--code-bg, #f6f6f6);
}
#bayes-sim .sim-prior-ctl label {
font-weight: 600;
}
#bayes-sim .sim-prior-ctl input[type="range"] {
width: 100%;
max-width: 360px;
display: block;
margin-top: 0.4em;
}
#bayes-sim .sim-wrap {
overflow-x: auto;
margin-bottom: 1.5em;
}
#bayes-sim table {
width: 100%;
border-collapse: collapse;
font-size: 0.88em;
}
#bayes-sim th,
#bayes-sim td {
padding: 0.4em 0.6em;
border-bottom: 1px solid var(--border, #ddd);
}
#bayes-sim th {
text-align: left;
font-weight: 600;
white-space: nowrap;
}
#bayes-sim .ev-name {
min-width: 150px;
}
#bayes-sim .sl-cell {
white-space: nowrap;
}
#bayes-sim .sl-cell input[type="range"] {
width: 80px;
vertical-align: middle;
}
#bayes-sim .v {
display: inline-block;
width: 2.8em;
text-align: right;
font-variant-numeric: tabular-nums;
font-size: 0.92em;
}
#bayes-sim .lr-cell {
text-align: right;
font-variant-numeric: tabular-nums;
}
#bayes-sim .bars {
margin-top: 0.5em;
}
#bayes-sim .b-row {
display: flex;
align-items: center;
margin-bottom: 3px;
}
#bayes-sim .b-lbl {
width: 190px;
font-size: 0.82em;
text-align: right;
padding-right: 8px;
flex-shrink: 0;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
#bayes-sim .b-track {
flex: 1;
height: 18px;
background: var(--code-bg, #f0f0f0);
border-radius: 3px;
overflow: hidden;
}
#bayes-sim .b-fill {
height: 100%;
background: var(--primary, #2c3e50);
border-radius: 3px;
transition: width 0.15s ease;
min-width: 0;
}
#bayes-sim .b-pct {
width: 4.5em;
font-size: 0.82em;
text-align: right;
padding-left: 6px;
font-variant-numeric: tabular-nums;
flex-shrink: 0;
}
#bayes-sim .sim-actions {
margin-top: 1em;
}
#bayes-sim button {
padding: 0.35em 0.9em;
border: 1px solid var(--border, #ddd);
border-radius: 4px;
background: var(--code-bg, #f6f6f6);
color: var(--content, #333);
cursor: pointer;
font-size: 0.88em;
}
#bayes-sim button:hover {
background: var(--border, #ddd);
}
#bayes-sim .cb {
width: 15px;
height: 15px;
cursor: pointer;
}
</style>
<div id="bayes-sim">
<div class="sim-prior-ctl">
<label for="sim-prior">Prior probability P(A): <span id="sim-prior-v">1.0%</span></label>
<input type="range" id="sim-prior" min="0.001" max="0.500" step="0.001" value="0.010">
</div>
<div class="sim-wrap">
<table>
<thead>
<tr>
<th></th>
<th>Event</th>
<th>P(E|A)</th>
<th>P(E|¬A)</th>
<th style="text-align:right">LR</th>
</tr>
</thead>
<tbody id="sim-tb"></tbody>
</table>
</div>
<div class="bars" id="sim-bars"></div>
<div class="sim-actions">
<button id="sim-reset">Reset to defaults</button>
</div>
</div>
<script>
(function () {
var E = [
{n:"Firing Inspectors General", h:0.90, a:0.10},
{n:"Shutting Down USAID", h:0.80, a:0.03},
{n:"Accessing Gov. Systems", h:0.70, a:0.15},
{n:"Mass Firing Fed. Workers", h:0.90, a:0.10},
{n:"Exec. Law Interpretation", h:0.80, a:0.10},
{n:"\"Long Live the King\"", h:0.70, a:0.10},
{n:"Kash Patel as FBI Dir.", h:0.85, a:0.05},
{n:"Firing Military Leadership", h:0.75, a:0.05}
];
var DP = 0.01;
var D = E.map(function(e){return {h:e.h, a:e.a};});
var ps = document.getElementById("sim-prior");
var pv = document.getElementById("sim-prior-v");
var tb = document.getElementById("sim-tb");
var bd = document.getElementById("sim-bars");
// Build table rows
E.forEach(function(e, i) {
var tr = document.createElement("tr");
var c1 = document.createElement("td");
var cb = document.createElement("input");
cb.type = "checkbox"; cb.checked = true;
cb.className = "cb"; cb.dataset.i = i;
cb.addEventListener("change", up);
c1.appendChild(cb); tr.appendChild(c1);
var c2 = document.createElement("td");
c2.className = "ev-name"; c2.textContent = e.n;
tr.appendChild(c2);
tr.appendChild(mkSlider(i, "h", e.h));
tr.appendChild(mkSlider(i, "a", e.a));
var c5 = document.createElement("td");
c5.className = "lr-cell"; c5.id = "lr"+i;
tr.appendChild(c5);
tb.appendChild(tr);
});
// Build bar chart
mkBar("prior", "Prior");
E.forEach(function(e, i){ mkBar(i, e.n); });
function mkSlider(i, t, val) {
var td = document.createElement("td");
td.className = "sl-cell";
var s = document.createElement("input");
s.type = "range"; s.min = "0.01"; s.max = "0.99";
s.step = "0.01"; s.value = val; s.id = t+i;
s.addEventListener("input", up);
var v = document.createElement("span");
v.className = "v"; v.id = t+"v"+i;
td.appendChild(s); td.appendChild(v);
return td;
}
function mkBar(id, label) {
var r = document.createElement("div");
r.className = "b-row"; r.id = "br"+id;
r.innerHTML =
'<span class="b-lbl">' + label + '</span>' +
'<div class="b-track"><div class="b-fill" id="bf'+id+'"></div></div>' +
'<span class="b-pct" id="bp'+id+'"></span>';
bd.appendChild(r);
}
function fmt(p) {
var pct = p * 100;
return pct < 99.95 ? pct.toFixed(1) + "%" : ">99.9%";
}
function up() {
var pr = parseFloat(ps.value);
pv.textContent = fmt(pr);
var odds = pr / (1 - pr);
document.getElementById("bfprior").style.width = (pr*100)+"%";
document.getElementById("bpprior").textContent = fmt(pr);
for (var i = 0; i < E.length; i++) {
var h = parseFloat(document.getElementById("h"+i).value);
var a = parseFloat(document.getElementById("a"+i).value);
document.getElementById("hv"+i).textContent = h.toFixed(2);
document.getElementById("av"+i).textContent = a.toFixed(2);
var lr = h / a;
document.getElementById("lr"+i).textContent = lr.toFixed(1);
var on = tb.querySelectorAll(".cb")[i].checked;
if (on) odds *= lr;
var p = odds / (1 + odds);
document.getElementById("bf"+i).style.width = (p*100)+"%";
var row = document.getElementById("br"+i);
if (on) {
row.style.opacity = "1";
document.getElementById("bp"+i).textContent = fmt(p);
} else {
row.style.opacity = "0.35";
document.getElementById("bp"+i).textContent = "\u2014";
}
}
}
document.getElementById("sim-reset").addEventListener("click", function() {
ps.value = DP;
for (var i = 0; i < E.length; i++) {
document.getElementById("h"+i).value = D[i].h;
document.getElementById("a"+i).value = D[i].a;
tb.querySelectorAll(".cb")[i].checked = true;
}
up();
});
ps.addEventListener("input", up);
up();
})();
</script>
[interactive simulator](simulator/) lets you adjust the prior probability
and each event's likelihoods to see how your own assumptions change the
conclusion.
## Discussion
@@ -730,7 +466,7 @@ assessments. Reasonable people will disagree. The value of this framework is not
that it produces a single "correct" answer, but that it forces us to state our
assumptions explicitly and see their consequences. If you think the likelihood
of mass IG firings under aggressive-but-not-coup governance is 30% rather than
10%, try it in the simulator above and see how the posterior changes.
10%, try it in the [simulator](simulator/) and see how the posterior changes.
**Independence assumption.** The odds form of Bayes' theorem assumes that
the pieces of evidence are _conditionally independent_---that is, knowing one
@@ -0,0 +1,288 @@
---
title: 'Bayesian Autogolpe Simulator'
description: >
Adjust the prior probability and each event's likelihoods to see how
your own assumptions change the conclusion.
ShowToc: false
---
The likelihood ratios in the [analysis](..) are my assessments. You may
disagree. The simulator below lets you adjust the prior probability and each
event's likelihoods to see how your own assumptions change the conclusion. You
can also uncheck events to exclude them entirely.
<style>
#bayes-sim {
margin: 1.5em 0;
font-family: inherit;
line-height: 1.4;
}
#bayes-sim .sim-prior-ctl {
margin-bottom: 1.5em;
padding: 1em;
border: 1px solid var(--border, #ddd);
border-radius: 6px;
background: var(--code-bg, #f6f6f6);
}
#bayes-sim .sim-prior-ctl label {
font-weight: 600;
}
#bayes-sim .sim-prior-ctl input[type="range"] {
width: 100%;
max-width: 360px;
display: block;
margin-top: 0.4em;
}
#bayes-sim .sim-wrap {
overflow-x: auto;
margin-bottom: 1.5em;
}
#bayes-sim table {
width: 100%;
border-collapse: collapse;
font-size: 0.88em;
}
#bayes-sim th,
#bayes-sim td {
padding: 0.4em 0.6em;
border-bottom: 1px solid var(--border, #ddd);
}
#bayes-sim th {
text-align: left;
font-weight: 600;
white-space: nowrap;
}
#bayes-sim .ev-name {
min-width: 150px;
}
#bayes-sim .sl-cell {
white-space: nowrap;
}
#bayes-sim .sl-cell input[type="range"] {
width: 80px;
vertical-align: middle;
}
#bayes-sim .v {
display: inline-block;
width: 2.8em;
text-align: right;
font-variant-numeric: tabular-nums;
font-size: 0.92em;
}
#bayes-sim .lr-cell {
text-align: right;
font-variant-numeric: tabular-nums;
}
#bayes-sim .bars {
margin-top: 0.5em;
}
#bayes-sim .b-row {
display: flex;
align-items: center;
margin-bottom: 3px;
}
#bayes-sim .b-lbl {
width: 190px;
font-size: 0.82em;
text-align: right;
padding-right: 8px;
flex-shrink: 0;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
#bayes-sim .b-track {
flex: 1;
height: 18px;
background: var(--code-bg, #f0f0f0);
border-radius: 3px;
overflow: hidden;
}
#bayes-sim .b-fill {
height: 100%;
background: var(--primary, #2c3e50);
border-radius: 3px;
transition: width 0.15s ease;
min-width: 0;
}
#bayes-sim .b-pct {
width: 4.5em;
font-size: 0.82em;
text-align: right;
padding-left: 6px;
font-variant-numeric: tabular-nums;
flex-shrink: 0;
}
#bayes-sim .sim-actions {
margin-top: 1em;
}
#bayes-sim button {
padding: 0.35em 0.9em;
border: 1px solid var(--border, #ddd);
border-radius: 4px;
background: var(--code-bg, #f6f6f6);
color: var(--content, #333);
cursor: pointer;
font-size: 0.88em;
}
#bayes-sim button:hover {
background: var(--border, #ddd);
}
#bayes-sim .cb {
width: 15px;
height: 15px;
cursor: pointer;
}
</style>
<div id="bayes-sim">
<div class="sim-prior-ctl">
<label for="sim-prior">Prior probability P(A): <span id="sim-prior-v">1.0%</span></label>
<input type="range" id="sim-prior" min="0.001" max="0.500" step="0.001" value="0.010">
</div>
<div class="sim-wrap">
<table>
<thead>
<tr>
<th></th>
<th>Event</th>
<th>P(E|A)</th>
<th>P(E|&not;A)</th>
<th style="text-align:right">LR</th>
</tr>
</thead>
<tbody id="sim-tb"></tbody>
</table>
</div>
<div class="bars" id="sim-bars"></div>
<div class="sim-actions">
<button id="sim-reset">Reset to defaults</button>
</div>
</div>
<script>
(function () {
var E = [
{n:"Firing Inspectors General", h:0.90, a:0.10},
{n:"Shutting Down USAID", h:0.80, a:0.03},
{n:"Accessing Gov. Systems", h:0.70, a:0.15},
{n:"Mass Firing Fed. Workers", h:0.90, a:0.10},
{n:"Exec. Law Interpretation", h:0.80, a:0.10},
{n:"\"Long Live the King\"", h:0.70, a:0.10},
{n:"Kash Patel as FBI Dir.", h:0.85, a:0.05},
{n:"Firing Military Leadership", h:0.75, a:0.05}
];
var DP = 0.01;
var D = E.map(function(e){return {h:e.h, a:e.a};});
var ps = document.getElementById("sim-prior");
var pv = document.getElementById("sim-prior-v");
var tb = document.getElementById("sim-tb");
var bd = document.getElementById("sim-bars");
// Build table rows
E.forEach(function(e, i) {
var tr = document.createElement("tr");
var c1 = document.createElement("td");
var cb = document.createElement("input");
cb.type = "checkbox"; cb.checked = true;
cb.className = "cb"; cb.dataset.i = i;
cb.addEventListener("change", up);
c1.appendChild(cb); tr.appendChild(c1);
var c2 = document.createElement("td");
c2.className = "ev-name"; c2.textContent = e.n;
tr.appendChild(c2);
tr.appendChild(mkSlider(i, "h", e.h));
tr.appendChild(mkSlider(i, "a", e.a));
var c5 = document.createElement("td");
c5.className = "lr-cell"; c5.id = "lr"+i;
tr.appendChild(c5);
tb.appendChild(tr);
});
// Build bar chart
mkBar("prior", "Prior");
E.forEach(function(e, i){ mkBar(i, e.n); });
function mkSlider(i, t, val) {
var td = document.createElement("td");
td.className = "sl-cell";
var s = document.createElement("input");
s.type = "range"; s.min = "0.01"; s.max = "0.99";
s.step = "0.01"; s.value = val; s.id = t+i;
s.addEventListener("input", up);
var v = document.createElement("span");
v.className = "v"; v.id = t+"v"+i;
td.appendChild(s); td.appendChild(v);
return td;
}
function mkBar(id, label) {
var r = document.createElement("div");
r.className = "b-row"; r.id = "br"+id;
r.innerHTML =
'<span class="b-lbl">' + label + '</span>' +
'<div class="b-track"><div class="b-fill" id="bf'+id+'"></div></div>' +
'<span class="b-pct" id="bp'+id+'"></span>';
bd.appendChild(r);
}
function fmt(p) {
var pct = p * 100;
return pct < 99.95 ? pct.toFixed(1) + "%" : ">99.9%";
}
function up() {
var pr = parseFloat(ps.value);
pv.textContent = fmt(pr);
var odds = pr / (1 - pr);
document.getElementById("bfprior").style.width = (pr*100)+"%";
document.getElementById("bpprior").textContent = fmt(pr);
for (var i = 0; i < E.length; i++) {
var h = parseFloat(document.getElementById("h"+i).value);
var a = parseFloat(document.getElementById("a"+i).value);
document.getElementById("hv"+i).textContent = h.toFixed(2);
document.getElementById("av"+i).textContent = a.toFixed(2);
var lr = h / a;
document.getElementById("lr"+i).textContent = lr.toFixed(1);
var on = tb.querySelectorAll(".cb")[i].checked;
if (on) odds *= lr;
var p = odds / (1 + odds);
document.getElementById("bf"+i).style.width = (p*100)+"%";
var row = document.getElementById("br"+i);
if (on) {
row.style.opacity = "1";
document.getElementById("bp"+i).textContent = fmt(p);
} else {
row.style.opacity = "0.35";
document.getElementById("bp"+i).textContent = "\u2014";
}
}
}
document.getElementById("sim-reset").addEventListener("click", function() {
ps.value = DP;
for (var i = 0; i < E.length; i++) {
document.getElementById("h"+i).value = D[i].h;
document.getElementById("a"+i).value = D[i].a;
tb.querySelectorAll(".cb")[i].checked = true;
}
up();
});
ps.addEventListener("input", up);
up();
})();
</script>