Add Artemis stress test for detecting cache aliasing bugs. Include statistical hypothesis evaluations, fix validation data, and run reports for validation across architectures.

Signed-off-by: Robert Allan James <robert.allan.james@gmail.com>
This commit is contained in:
Robert Allan James
2026-08-02 14:49:52 -04:00
parent 148c4aa12c
commit 1cb68502fb
44 changed files with 5610173 additions and 2680 deletions
@@ -0,0 +1,269 @@
#!/usr/bin/env Rscript
# analyse_artemis_stress.R
#
# Analysis for the Artemis surface stress test bug hunt (2026-08-02):
# a stale-pointer aliasing bug between the block-subsystem's devblock
# cache and the VM-level window cache in src/word_source/block_words.c,
# found by the first completed run of ART-STRESS-TEST, fixed, and
# re-verified on all three architectures.
#
# Reads experiments/artemis_stress/runs/*.csv, writes SVG charts to
# analysis/charts/ and PNG copies to analysis/img/.
suppressMessages({
library(ggplot2)
library(dplyr)
library(tidyr)
library(scales)
library(svglite)
})
run_dir <- file.path("experiments", "artemis_stress", "runs")
chart_dir <- file.path("experiments", "artemis_stress", "analysis", "charts")
img_dir <- file.path("experiments", "artemis_stress", "analysis", "img")
dir.create(chart_dir, recursive = TRUE, showWarnings = FALSE)
dir.create(img_dir, recursive = TRUE, showWarnings = FALSE)
## ---- palette (matches experiments/bare_metal house style) ----
sfblue <- "#1F77B4"
sforange <- "#FF7F0E"
sfgreen <- "#2CA02C"
sfred <- "#D62728"
sfgray <- "#505050"
theme_sf <- function() {
theme_minimal(base_size = 12) +
theme(
panel.grid.minor = element_blank(),
plot.title = element_text(face = "bold"),
plot.subtitle = element_text(color = sfgray),
legend.position = "bottom"
)
}
save_chart <- function(plot, name, width = 7, height = 4.2) {
svg_path <- file.path(chart_dir, paste0(name, ".svg"))
png_path <- file.path(img_dir, paste0(name, ".png"))
ggsave(svg_path, plot, width = width, height = height, device = svglite)
ggsave(png_path, plot, width = width, height = height, dpi = 200)
cat(" wrote", svg_path, "and", png_path, "\n")
}
## ---- load runs ----
runs <- list(
amd64_buggy = "amd64 (pre-fix)",
amd64_fixed = "amd64 (post-fix)",
aarch64_fixed = "aarch64 (post-fix)",
riscv64_fixed = "riscv64 (post-fix)"
)
load_run <- function(key, label) {
df <- read.csv(file.path(run_dir, paste0(key, ".csv")))
df$run <- key
df$label <- label
df$status <- factor(ifelse(df$result == 1, "PASS", "FAIL"), levels = c("PASS", "FAIL"))
df
}
all_runs <- bind_rows(Map(load_run, names(runs), runs))
## ---- Chart 1: pass rate before/after, all runs ----
summary_tbl <- all_runs %>%
group_by(run, label) %>%
summarise(n = n(), passed = sum(result), .groups = "drop") %>%
mutate(pass_rate = passed / n,
phase = ifelse(grepl("pre-fix", label), "pre-fix", "post-fix"))
p1 <- ggplot(summary_tbl, aes(x = reorder(label, pass_rate), y = pass_rate, fill = phase)) +
geom_col(width = 0.6) +
geom_text(aes(label = sprintf("%d/%d", passed, n)), vjust = -0.5, size = 4) +
scale_y_continuous(labels = percent_format(), limits = c(0, 1.08)) +
scale_fill_manual(values = c("pre-fix" = sfred, "post-fix" = sfgreen)) +
coord_flip() +
labs(
title = "Artemis surface stress test: pass rate before/after fix",
subtitle = "50 trials per run, unique random blocks across the 22998-block data pool",
x = NULL, y = "Pass rate", fill = NULL
) +
theme_sf()
save_chart(p1, "pass_rate_comparison", width = 8)
## ---- Chart 2: pass/fail sequence in write/verify order, buggy run ----
## A visual scan of this sequence first suggested serial clustering; the
## Wald-Wolfowitz runs test (H1, below) does not support that reading --
## observed runs (26) exactly match the count expected under a random
## ordering. The chart is kept because it is still the raw sequence the
## tests are run against, not because it shows a confirmed pattern.
buggy <- all_runs %>% filter(run == "amd64_buggy") %>% arrange(trial)
p2 <- ggplot(buggy, aes(x = trial, y = 1, fill = status)) +
geom_tile(color = "white", linewidth = 0.6, height = 1) +
scale_fill_manual(values = c(PASS = sfgreen, FAIL = sfred)) +
scale_x_continuous(breaks = seq(0, 49, 5)) +
labs(
title = "Pass/fail sequence in write order, amd64 pre-fix run",
subtitle = "25 of 50 trials failed; a formal runs test (H1) finds no\nsignificant serial clustering in this sequence -- see Section 4",
x = "Trial index (= write/verify order)", y = NULL, fill = NULL
) +
theme_sf() +
theme(axis.text.y = element_blank(), panel.grid = element_blank())
save_chart(p2, "failure_clustering", height = 2.6)
## ---- Chart 3: surface coverage map, buggy vs one fixed run ----
cov <- all_runs %>% filter(run %in% c("amd64_buggy", "amd64_fixed"))
p3 <- ggplot(cov, aes(x = lbn, y = trial, color = status)) +
geom_point(size = 2.2, alpha = 0.85) +
scale_color_manual(values = c(PASS = sfgreen, FAIL = sfred)) +
facet_wrap(~label, ncol = 1) +
labs(
title = "Surface coverage: scattered across the full data pool",
subtitle = "Each point is one trial's block. A Wilcoxon test (H2) finds LBN and\noutcome are not independent, but no sub-region is visually implicated",
x = "Logical block number (data pool: 3076-26073)", y = "Trial index", color = NULL
) +
theme_sf()
save_chart(p3, "surface_coverage_map", height = 5.5)
## ---- summary table for the report ----
write.csv(summary_tbl, file.path("experiments", "artemis_stress", "analysis", "summary.csv"),
row.names = FALSE)
cat("\nDone. Summary:\n")
print(as.data.frame(summary_tbl))
## ═══════════════════════════════════════════════════════════════════════
## Hypothesis tests
##
## Three questions, each with an explicit null hypothesis, tested against
## the actual recorded trial data rather than asserted from eyeballing
## charts. Results are written to tables/ for the LaTeX report to quote
## verbatim -- no numbers in the report are hand-typed.
## ═══════════════════════════════════════════════════════════════════════
table_dir <- file.path("experiments", "artemis_stress", "analysis", "tables")
dir.create(table_dir, recursive = TRUE, showWarnings = FALSE)
sink_lines <- c()
say <- function(...) {
line <- paste0(...)
sink_lines <<- c(sink_lines, line)
cat(line, "\n")
}
say("Artemis surface stress test -- hypothesis tests")
say("=================================================")
say("")
## ---- H1: are pre-fix failures independently distributed across trials, ----
## ---- or do they show serial clustering (a runs test)? ----
## H0: the pass/fail sequence is a random ordering (no serial correlation).
## Manual Wald-Wolfowitz runs test (base R only, no extra package needed).
runs_test <- function(seq01) {
n1 <- sum(seq01 == 1); n2 <- sum(seq01 == 0); n <- n1 + n2
r <- 1 + sum(diff(seq01) != 0)
mu <- 1 + 2 * n1 * n2 / n
var_r <- (2 * n1 * n2 * (2 * n1 * n2 - n)) / (n^2 * (n - 1))
z <- (r - mu) / sqrt(var_r)
p <- 2 * pnorm(-abs(z))
list(n1 = n1, n2 = n2, runs = r, expected = mu, z = z, p = p)
}
buggy_seq <- buggy$result[order(buggy$trial)]
rt <- runs_test(buggy_seq)
say("H1 -- pre-fix failure clustering (Wald-Wolfowitz runs test)")
say(" H0: pass/fail outcomes are independently ordered (no clustering).")
say(sprintf(" Observed runs = %d (expected under H0 = %.2f, sd = %.2f)",
rt$runs, rt$expected, sqrt((2*rt$n1*rt$n2*(2*rt$n1*rt$n2-(rt$n1+rt$n2))) /
((rt$n1+rt$n2)^2*(rt$n1+rt$n2-1)))))
say(sprintf(" z = %.3f, p = %.2e", rt$z, rt$p))
say(sprintf(" -> %s H0 at alpha=0.05: failures %s serially clustered.",
ifelse(rt$p < 0.05, "REJECT", "fail to reject"),
ifelse(rt$p < 0.05, "ARE", "are not")))
say("")
## ---- H1b: is outcome associated with trial/write order directly ----
## ---- (not via the runs test, which only detects consecutive-value ----
## ---- clustering and can miss a more general order-dependent trend)? ----
## H0: trial index is drawn from the same distribution for PASS and FAIL.
wt_order <- wilcox.test(trial ~ status, data = buggy)
say("H1b -- pre-fix outcome vs. trial/write order directly (Wilcoxon)")
say(" H0: trial index is drawn from the same distribution for PASS/FAIL")
say(" (complements H1: the runs test only catches consecutive-value")
say(" clustering, not a general rank-order trend).")
say(sprintf(" W = %.1f, p = %.3f", wt_order$statistic, wt_order$p.value))
say(sprintf(" -> %s H0 at alpha=0.05: outcome %s associated with write order.",
ifelse(wt_order$p.value < 0.05, "REJECT", "fail to reject"),
ifelse(wt_order$p.value < 0.05, "IS", "is not")))
say("")
## ---- H2: is failure status independent of disk location (logical ----
## ---- block number)? ----
## H0: LBN is drawn from the same distribution for PASS and FAIL trials.
## Wilcoxon rank-sum test (non-parametric, no normality assumption on LBN).
wt <- wilcox.test(lbn ~ status, data = buggy)
say("H2 -- pre-fix failure vs. disk location (Wilcoxon rank-sum test)")
say(" H0: logical block number is drawn from the same distribution")
say(" for PASS and FAIL trials (failure does not depend on location).")
say(sprintf(" W = %.1f, p = %.3f", wt$statistic, wt$p.value))
say(sprintf(" -> %s H0 at alpha=0.05: failure %s associated with LBN.",
ifelse(wt$p.value < 0.05, "REJECT", "fail to reject"),
ifelse(wt$p.value < 0.05, "IS", "is not")))
say("")
## Secondary check: sibling position within devblock (0/1/2).
buggy$sib_pos <- (buggy$lbn - 3076) %% 3
pos_tbl <- table(buggy$sib_pos, buggy$status)
ct <- suppressWarnings(chisq.test(pos_tbl))
say(" Secondary check -- sibling position (0/1/2) vs. outcome (chi-squared)")
say(sprintf(" chi-sq = %.3f, df = %d, p = %.3f",
ct$statistic, ct$parameter, ct$p.value))
say(sprintf(" -> %s H0: outcome %s associated with sibling position.",
ifelse(ct$p.value < 0.05, "REJECT", "fail to reject"),
ifelse(ct$p.value < 0.05, "IS", "is not")))
say("")
## ---- H3: did the fix change the pass rate, or is 25/50 vs 150/150 ----
## ---- explainable by chance? ----
## H0: pre-fix and post-fix runs share the same true pass probability.
post_passed <- sum(all_runs$run != "amd64_buggy" & all_runs$result == 1)
post_n <- sum(all_runs$run != "amd64_buggy")
pre_passed <- sum(all_runs$run == "amd64_buggy" & all_runs$result == 1)
pre_n <- sum(all_runs$run == "amd64_buggy")
pt <- prop.test(c(pre_passed, post_passed), c(pre_n, post_n), correct = TRUE)
say("H3 -- did the fix change the pass rate (two-proportion test)")
say(" H0: pre-fix and post-fix trials share the same true pass rate.")
say(sprintf(" Pre-fix: %d/%d = %.1f%% Post-fix (pooled, 3 arches): %d/%d = %.1f%%",
pre_passed, pre_n, 100*pre_passed/pre_n,
post_passed, post_n, 100*post_passed/post_n))
say(sprintf(" chi-sq = %.2f, df = %d, p = %.2e", pt$statistic, 1, pt$p.value))
say(sprintf(" 95%% CI on the difference in pass rate: [%.3f, %.3f]",
pt$conf.int[1], pt$conf.int[2]))
say(sprintf(" -> %s H0 at alpha=0.05: the fix %s the pass rate.",
ifelse(pt$p.value < 0.05, "REJECT", "fail to reject"),
ifelse(pt$p.value < 0.05, "DID CHANGE", "did not measurably change")))
writeLines(sink_lines, file.path(table_dir, "hypothesis_tests.txt"))
## Machine-readable version for \newcommand substitution in the report.
hyp_df <- data.frame(
key = c("h1_runs_obs","h1_runs_exp","h1_z","h1_p",
"h1b_W","h1b_p",
"h2_W","h2_p","h2b_chisq","h2b_df","h2b_p",
"h3_pre_n","h3_pre_pass","h3_post_n","h3_post_pass",
"h3_chisq","h3_p","h3_ci_lo","h3_ci_hi"),
value = c(rt$runs, rt$expected, rt$z, rt$p,
unname(wt_order$statistic), wt_order$p.value,
unname(wt$statistic), wt$p.value, unname(ct$statistic), unname(ct$parameter), ct$p.value,
pre_n, pre_passed, post_n, post_passed,
unname(pt$statistic), pt$p.value, pt$conf.int[1], pt$conf.int[2])
)
write.csv(hyp_df, file.path(table_dir, "hypothesis_tests.csv"), row.names = FALSE)
cat("\nWrote", file.path(table_dir, "hypothesis_tests.txt"), "and .csv\n")
@@ -0,0 +1,208 @@
<?xml version='1.0' encoding='UTF-8' ?>
<svg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' width='504.00pt' height='187.20pt'
viewBox='0 0 504.00 187.20'>
<g class='svglite'>
<defs>
<style type='text/css'><![CDATA[
.svglite line, .svglite polyline, .svglite polygon, .svglite path, .svglite rect, .svglite circle {
fill: none;
stroke: #000000;
stroke-linecap: round;
stroke-linejoin: round;
stroke-miterlimit: 10.00;
}
.svglite text {
white-space: pre;
}
.svglite g.glyphgroup path {
fill: inherit;
stroke: none;
}
]]></style>
</defs>
<rect width='100%' height='100%' style='stroke: none; fill: #FFFFFF;'/>
<defs>
<clipPath id='cpMC4wMHw1MDQuMDB8MC4wMHwxODcuMjA='>
<rect x='0.00' y='0.00' width='504.00' height='187.20'/>
</clipPath>
</defs>
<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHwxODcuMjA=)'>
<rect x='0.00' y='0.00' width='504.00' height='187.20'
style='stroke-width: 1.16; stroke: none; fill: #FFFFFF;'/>
</g>
<defs>
<clipPath id='cpNS45OHw0OTguMDJ8NTQuNTN8MTEyLjMz'>
<rect x='5.98' y='54.53' width='492.04' height='57.80'/>
</clipPath>
</defs>
<g clip-path='url(#cpNS45OHw0OTguMDJ8NTQuNTN8MTEyLjMz)'>
<rect x='28.34' y='57.16' width='8.95' height='52.55'
style='stroke-width: 1.28; stroke: #FFFFFF; stroke-linecap: butt; stroke-linejoin: miter; fill: #D62728;'/>
<rect x='37.29' y='57.16' width='8.95' height='52.55'
style='stroke-width: 1.28; stroke: #FFFFFF; stroke-linecap: butt; stroke-linejoin: miter; fill: #D62728;'/>
<rect x='46.24' y='57.16' width='8.95' height='52.55'
style='stroke-width: 1.28; stroke: #FFFFFF; stroke-linecap: butt; stroke-linejoin: miter; fill: #D62728;'/>
<rect x='55.18' y='57.16' width='8.95' height='52.55'
style='stroke-width: 1.28; stroke: #FFFFFF; stroke-linecap: butt; stroke-linejoin: miter; fill: #2CA02C;'/>
<rect x='64.13' y='57.16' width='8.95' height='52.55'
style='stroke-width: 1.28; stroke: #FFFFFF; stroke-linecap: butt; stroke-linejoin: miter; fill: #2CA02C;'/>
<rect x='73.07' y='57.16' width='8.95' height='52.55'
style='stroke-width: 1.28; stroke: #FFFFFF; stroke-linecap: butt; stroke-linejoin: miter; fill: #D62728;'/>
<rect x='82.02' y='57.16' width='8.95' height='52.55'
style='stroke-width: 1.28; stroke: #FFFFFF; stroke-linecap: butt; stroke-linejoin: miter; fill: #2CA02C;'/>
<rect x='90.97' y='57.16' width='8.95' height='52.55'
style='stroke-width: 1.28; stroke: #FFFFFF; stroke-linecap: butt; stroke-linejoin: miter; fill: #2CA02C;'/>
<rect x='99.91' y='57.16' width='8.95' height='52.55'
style='stroke-width: 1.28; stroke: #FFFFFF; stroke-linecap: butt; stroke-linejoin: miter; fill: #D62728;'/>
<rect x='108.86' y='57.16' width='8.95' height='52.55'
style='stroke-width: 1.28; stroke: #FFFFFF; stroke-linecap: butt; stroke-linejoin: miter; fill: #D62728;'/>
<rect x='117.81' y='57.16' width='8.95' height='52.55'
style='stroke-width: 1.28; stroke: #FFFFFF; stroke-linecap: butt; stroke-linejoin: miter; fill: #2CA02C;'/>
<rect x='126.75' y='57.16' width='8.95' height='52.55'
style='stroke-width: 1.28; stroke: #FFFFFF; stroke-linecap: butt; stroke-linejoin: miter; fill: #D62728;'/>
<rect x='135.70' y='57.16' width='8.95' height='52.55'
style='stroke-width: 1.28; stroke: #FFFFFF; stroke-linecap: butt; stroke-linejoin: miter; fill: #2CA02C;'/>
<rect x='144.64' y='57.16' width='8.95' height='52.55'
style='stroke-width: 1.28; stroke: #FFFFFF; stroke-linecap: butt; stroke-linejoin: miter; fill: #2CA02C;'/>
<rect x='153.59' y='57.16' width='8.95' height='52.55'
style='stroke-width: 1.28; stroke: #FFFFFF; stroke-linecap: butt; stroke-linejoin: miter; fill: #2CA02C;'/>
<rect x='162.54' y='57.16' width='8.95' height='52.55'
style='stroke-width: 1.28; stroke: #FFFFFF; stroke-linecap: butt; stroke-linejoin: miter; fill: #2CA02C;'/>
<rect x='171.48' y='57.16' width='8.95' height='52.55'
style='stroke-width: 1.28; stroke: #FFFFFF; stroke-linecap: butt; stroke-linejoin: miter; fill: #2CA02C;'/>
<rect x='180.43' y='57.16' width='8.95' height='52.55'
style='stroke-width: 1.28; stroke: #FFFFFF; stroke-linecap: butt; stroke-linejoin: miter; fill: #D62728;'/>
<rect x='189.38' y='57.16' width='8.95' height='52.55'
style='stroke-width: 1.28; stroke: #FFFFFF; stroke-linecap: butt; stroke-linejoin: miter; fill: #D62728;'/>
<rect x='198.32' y='57.16' width='8.95' height='52.55'
style='stroke-width: 1.28; stroke: #FFFFFF; stroke-linecap: butt; stroke-linejoin: miter; fill: #2CA02C;'/>
<rect x='207.27' y='57.16' width='8.95' height='52.55'
style='stroke-width: 1.28; stroke: #FFFFFF; stroke-linecap: butt; stroke-linejoin: miter; fill: #D62728;'/>
<rect x='216.21' y='57.16' width='8.95' height='52.55'
style='stroke-width: 1.28; stroke: #FFFFFF; stroke-linecap: butt; stroke-linejoin: miter; fill: #D62728;'/>
<rect x='225.16' y='57.16' width='8.95' height='52.55'
style='stroke-width: 1.28; stroke: #FFFFFF; stroke-linecap: butt; stroke-linejoin: miter; fill: #2CA02C;'/>
<rect x='234.11' y='57.16' width='8.95' height='52.55'
style='stroke-width: 1.28; stroke: #FFFFFF; stroke-linecap: butt; stroke-linejoin: miter; fill: #2CA02C;'/>
<rect x='243.05' y='57.16' width='8.95' height='52.55'
style='stroke-width: 1.28; stroke: #FFFFFF; stroke-linecap: butt; stroke-linejoin: miter; fill: #D62728;'/>
<rect x='252.00' y='57.16' width='8.95' height='52.55'
style='stroke-width: 1.28; stroke: #FFFFFF; stroke-linecap: butt; stroke-linejoin: miter; fill: #D62728;'/>
<rect x='260.95' y='57.16' width='8.95' height='52.55'
style='stroke-width: 1.28; stroke: #FFFFFF; stroke-linecap: butt; stroke-linejoin: miter; fill: #D62728;'/>
<rect x='269.89' y='57.16' width='8.95' height='52.55'
style='stroke-width: 1.28; stroke: #FFFFFF; stroke-linecap: butt; stroke-linejoin: miter; fill: #2CA02C;'/>
<rect x='278.84' y='57.16' width='8.95' height='52.55'
style='stroke-width: 1.28; stroke: #FFFFFF; stroke-linecap: butt; stroke-linejoin: miter; fill: #2CA02C;'/>
<rect x='287.79' y='57.16' width='8.95' height='52.55'
style='stroke-width: 1.28; stroke: #FFFFFF; stroke-linecap: butt; stroke-linejoin: miter; fill: #D62728;'/>
<rect x='296.73' y='57.16' width='8.95' height='52.55'
style='stroke-width: 1.28; stroke: #FFFFFF; stroke-linecap: butt; stroke-linejoin: miter; fill: #D62728;'/>
<rect x='305.68' y='57.16' width='8.95' height='52.55'
style='stroke-width: 1.28; stroke: #FFFFFF; stroke-linecap: butt; stroke-linejoin: miter; fill: #D62728;'/>
<rect x='314.62' y='57.16' width='8.95' height='52.55'
style='stroke-width: 1.28; stroke: #FFFFFF; stroke-linecap: butt; stroke-linejoin: miter; fill: #2CA02C;'/>
<rect x='323.57' y='57.16' width='8.95' height='52.55'
style='stroke-width: 1.28; stroke: #FFFFFF; stroke-linecap: butt; stroke-linejoin: miter; fill: #D62728;'/>
<rect x='332.52' y='57.16' width='8.95' height='52.55'
style='stroke-width: 1.28; stroke: #FFFFFF; stroke-linecap: butt; stroke-linejoin: miter; fill: #D62728;'/>
<rect x='341.46' y='57.16' width='8.95' height='52.55'
style='stroke-width: 1.28; stroke: #FFFFFF; stroke-linecap: butt; stroke-linejoin: miter; fill: #D62728;'/>
<rect x='350.41' y='57.16' width='8.95' height='52.55'
style='stroke-width: 1.28; stroke: #FFFFFF; stroke-linecap: butt; stroke-linejoin: miter; fill: #2CA02C;'/>
<rect x='359.36' y='57.16' width='8.95' height='52.55'
style='stroke-width: 1.28; stroke: #FFFFFF; stroke-linecap: butt; stroke-linejoin: miter; fill: #2CA02C;'/>
<rect x='368.30' y='57.16' width='8.95' height='52.55'
style='stroke-width: 1.28; stroke: #FFFFFF; stroke-linecap: butt; stroke-linejoin: miter; fill: #D62728;'/>
<rect x='377.25' y='57.16' width='8.95' height='52.55'
style='stroke-width: 1.28; stroke: #FFFFFF; stroke-linecap: butt; stroke-linejoin: miter; fill: #2CA02C;'/>
<rect x='386.19' y='57.16' width='8.95' height='52.55'
style='stroke-width: 1.28; stroke: #FFFFFF; stroke-linecap: butt; stroke-linejoin: miter; fill: #D62728;'/>
<rect x='395.14' y='57.16' width='8.95' height='52.55'
style='stroke-width: 1.28; stroke: #FFFFFF; stroke-linecap: butt; stroke-linejoin: miter; fill: #2CA02C;'/>
<rect x='404.09' y='57.16' width='8.95' height='52.55'
style='stroke-width: 1.28; stroke: #FFFFFF; stroke-linecap: butt; stroke-linejoin: miter; fill: #2CA02C;'/>
<rect x='413.03' y='57.16' width='8.95' height='52.55'
style='stroke-width: 1.28; stroke: #FFFFFF; stroke-linecap: butt; stroke-linejoin: miter; fill: #D62728;'/>
<rect x='421.98' y='57.16' width='8.95' height='52.55'
style='stroke-width: 1.28; stroke: #FFFFFF; stroke-linecap: butt; stroke-linejoin: miter; fill: #2CA02C;'/>
<rect x='430.93' y='57.16' width='8.95' height='52.55'
style='stroke-width: 1.28; stroke: #FFFFFF; stroke-linecap: butt; stroke-linejoin: miter; fill: #2CA02C;'/>
<rect x='439.87' y='57.16' width='8.95' height='52.55'
style='stroke-width: 1.28; stroke: #FFFFFF; stroke-linecap: butt; stroke-linejoin: miter; fill: #D62728;'/>
<rect x='448.82' y='57.16' width='8.95' height='52.55'
style='stroke-width: 1.28; stroke: #FFFFFF; stroke-linecap: butt; stroke-linejoin: miter; fill: #D62728;'/>
<rect x='457.76' y='57.16' width='8.95' height='52.55'
style='stroke-width: 1.28; stroke: #FFFFFF; stroke-linecap: butt; stroke-linejoin: miter; fill: #2CA02C;'/>
<rect x='466.71' y='57.16' width='8.95' height='52.55'
style='stroke-width: 1.28; stroke: #FFFFFF; stroke-linecap: butt; stroke-linejoin: miter; fill: #2CA02C;'/>
</g>
<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHwxODcuMjA=)'>
<text x='32.82' y='124.31' text-anchor='middle'
style='font-size: 9.60px;fill: #4D4D4D; font-family: "Liberation Sans";' textLength='5.33px'
lengthAdjust='spacingAndGlyphs'>0
</text>
<text x='77.55' y='124.31' text-anchor='middle'
style='font-size: 9.60px;fill: #4D4D4D; font-family: "Liberation Sans";' textLength='5.33px'
lengthAdjust='spacingAndGlyphs'>5
</text>
<text x='122.28' y='124.31' text-anchor='middle'
style='font-size: 9.60px;fill: #4D4D4D; font-family: "Liberation Sans";' textLength='10.66px'
lengthAdjust='spacingAndGlyphs'>10
</text>
<text x='167.01' y='124.31' text-anchor='middle'
style='font-size: 9.60px;fill: #4D4D4D; font-family: "Liberation Sans";' textLength='10.66px'
lengthAdjust='spacingAndGlyphs'>15
</text>
<text x='211.74' y='124.31' text-anchor='middle'
style='font-size: 9.60px;fill: #4D4D4D; font-family: "Liberation Sans";' textLength='10.66px'
lengthAdjust='spacingAndGlyphs'>20
</text>
<text x='256.47' y='124.31' text-anchor='middle'
style='font-size: 9.60px;fill: #4D4D4D; font-family: "Liberation Sans";' textLength='10.66px'
lengthAdjust='spacingAndGlyphs'>25
</text>
<text x='301.20' y='124.31' text-anchor='middle'
style='font-size: 9.60px;fill: #4D4D4D; font-family: "Liberation Sans";' textLength='10.66px'
lengthAdjust='spacingAndGlyphs'>30
</text>
<text x='345.94' y='124.31' text-anchor='middle'
style='font-size: 9.60px;fill: #4D4D4D; font-family: "Liberation Sans";' textLength='10.66px'
lengthAdjust='spacingAndGlyphs'>35
</text>
<text x='390.67' y='124.31' text-anchor='middle'
style='font-size: 9.60px;fill: #4D4D4D; font-family: "Liberation Sans";' textLength='10.66px'
lengthAdjust='spacingAndGlyphs'>40
</text>
<text x='435.40' y='124.31' text-anchor='middle'
style='font-size: 9.60px;fill: #4D4D4D; font-family: "Liberation Sans";' textLength='10.66px'
lengthAdjust='spacingAndGlyphs'>45
</text>
<text x='252.00' y='137.54' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";'
textLength='165.28px' lengthAdjust='spacingAndGlyphs'>Trial index (= write/verify order)
</text>
<rect x='204.28' y='158.82' width='15.58' height='15.58'
style='stroke-width: 1.28; stroke: #FFFFFF; stroke-linecap: butt; stroke-linejoin: miter; fill: #2CA02C;'/>
<rect x='258.43' y='158.82' width='15.58' height='15.58'
style='stroke-width: 1.28; stroke: #FFFFFF; stroke-linecap: butt; stroke-linejoin: miter; fill: #D62728;'/>
<text x='226.69' y='169.90' style='font-size: 9.60px; font-family: "Liberation Sans";' textLength='24.91px'
lengthAdjust='spacingAndGlyphs'>PASS
</text>
<text x='280.83' y='169.90' style='font-size: 9.60px; font-family: "Liberation Sans";' textLength='19.73px'
lengthAdjust='spacingAndGlyphs'>FAIL
</text>
<text x='5.98' y='33.10' style='font-size: 12.00px;fill: #505050; font-family: "Liberation Sans";'
textLength='275.38px' lengthAdjust='spacingAndGlyphs'>25 of 50 trials failed; a formal runs test (H1)
finds no
</text>
<text x='5.98' y='46.06' style='font-size: 12.00px;fill: #505050; font-family: "Liberation Sans";'
textLength='317.44px' lengthAdjust='spacingAndGlyphs'>significant serial clustering in this sequence
-- see Section 4
</text>
<text x='5.98' y='15.88' style='font-size: 14.40px; font-weight: bold; font-family: "Liberation Sans";'
textLength='351.91px' lengthAdjust='spacingAndGlyphs'>Pass/fail sequence in write order, amd64 pre-fix
run
</text>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 15 KiB

@@ -0,0 +1,132 @@
<?xml version='1.0' encoding='UTF-8' ?>
<svg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' width='576.00pt' height='302.40pt'
viewBox='0 0 576.00 302.40'>
<g class='svglite'>
<defs>
<style type='text/css'><![CDATA[
.svglite line, .svglite polyline, .svglite polygon, .svglite path, .svglite rect, .svglite circle {
fill: none;
stroke: #000000;
stroke-linecap: round;
stroke-linejoin: round;
stroke-miterlimit: 10.00;
}
.svglite text {
white-space: pre;
}
.svglite g.glyphgroup path {
fill: inherit;
stroke: none;
}
]]></style>
</defs>
<rect width='100%' height='100%' style='stroke: none; fill: #FFFFFF;'/>
<defs>
<clipPath id='cpMC4wMHw1NzYuMDB8MC4wMHwzMDIuNDA='>
<rect x='0.00' y='0.00' width='576.00' height='302.40'/>
</clipPath>
</defs>
<g clip-path='url(#cpMC4wMHw1NzYuMDB8MC4wMHwzMDIuNDA=)'>
<rect x='0.00' y='0.000000000000057' width='576.00' height='302.40'
style='stroke-width: 1.16; stroke: none; fill: #FFFFFF;'/>
</g>
<defs>
<clipPath id='cpODUuOTR8NTcwLjAyfDQxLjU3fDIyNy41Mw=='>
<rect x='85.94' y='41.57' width='484.09' height='185.96'/>
</clipPath>
</defs>
<g clip-path='url(#cpODUuOTR8NTcwLjAyfDQxLjU3fDIyNy41Mw==)'>
<polyline points='85.94,200.97 570.02,200.97 '
style='stroke-width: 1.16; stroke: #EBEBEB; stroke-linecap: butt;'/>
<polyline points='85.94,156.69 570.02,156.69 '
style='stroke-width: 1.16; stroke: #EBEBEB; stroke-linecap: butt;'/>
<polyline points='85.94,112.41 570.02,112.41 '
style='stroke-width: 1.16; stroke: #EBEBEB; stroke-linecap: butt;'/>
<polyline points='85.94,68.14 570.02,68.14 '
style='stroke-width: 1.16; stroke: #EBEBEB; stroke-linecap: butt;'/>
<polyline points='107.94,227.53 107.94,41.57 '
style='stroke-width: 1.16; stroke: #EBEBEB; stroke-linecap: butt;'/>
<polyline points='230.18,227.53 230.18,41.57 '
style='stroke-width: 1.16; stroke: #EBEBEB; stroke-linecap: butt;'/>
<polyline points='352.43,227.53 352.43,41.57 '
style='stroke-width: 1.16; stroke: #EBEBEB; stroke-linecap: butt;'/>
<polyline points='474.67,227.53 474.67,41.57 '
style='stroke-width: 1.16; stroke: #EBEBEB; stroke-linecap: butt;'/>
<rect x='107.94' y='143.41' width='407.48' height='26.57'
style='stroke-width: 1.16; stroke: none; stroke-linecap: butt; stroke-linejoin: miter; fill: #2CA02C;'/>
<rect x='107.94' y='187.68' width='203.74' height='26.57'
style='stroke-width: 1.16; stroke: none; stroke-linecap: butt; stroke-linejoin: miter; fill: #D62728;'/>
<rect x='107.94' y='99.13' width='407.48' height='26.57'
style='stroke-width: 1.16; stroke: none; stroke-linecap: butt; stroke-linejoin: miter; fill: #2CA02C;'/>
<rect x='107.94' y='54.85' width='407.48' height='26.57'
style='stroke-width: 1.16; stroke: none; stroke-linecap: butt; stroke-linejoin: miter; fill: #2CA02C;'/>
<text x='515.42' y='152.78' text-anchor='middle' style='font-size: 11.38px; font-family: "Liberation Sans";'
textLength='28.47px' lengthAdjust='spacingAndGlyphs'>50/50
</text>
<text x='311.68' y='197.05' text-anchor='middle' style='font-size: 11.38px; font-family: "Liberation Sans";'
textLength='28.47px' lengthAdjust='spacingAndGlyphs'>25/50
</text>
<text x='515.42' y='108.50' text-anchor='middle' style='font-size: 11.38px; font-family: "Liberation Sans";'
textLength='28.47px' lengthAdjust='spacingAndGlyphs'>50/50
</text>
<text x='515.42' y='64.22' text-anchor='middle' style='font-size: 11.38px; font-family: "Liberation Sans";'
textLength='28.47px' lengthAdjust='spacingAndGlyphs'>50/50
</text>
</g>
<g clip-path='url(#cpMC4wMHw1NzYuMDB8MC4wMHwzMDIuNDA=)'>
<text x='80.56' y='204.26' text-anchor='end'
style='font-size: 9.60px;fill: #4D4D4D; font-family: "Liberation Sans";' textLength='64.97px'
lengthAdjust='spacingAndGlyphs'>amd64 (pre-fix)
</text>
<text x='80.56' y='159.99' text-anchor='end'
style='font-size: 9.60px;fill: #4D4D4D; font-family: "Liberation Sans";' textLength='74.58px'
lengthAdjust='spacingAndGlyphs'>aarch64 (post-fix)
</text>
<text x='80.56' y='115.71' text-anchor='end'
style='font-size: 9.60px;fill: #4D4D4D; font-family: "Liberation Sans";' textLength='69.25px'
lengthAdjust='spacingAndGlyphs'>amd64 (post-fix)
</text>
<text x='80.56' y='71.43' text-anchor='end'
style='font-size: 9.60px;fill: #4D4D4D; font-family: "Liberation Sans";' textLength='70.31px'
lengthAdjust='spacingAndGlyphs'>riscv64 (post-fix)
</text>
<text x='107.94' y='239.51' text-anchor='middle'
style='font-size: 9.60px;fill: #4D4D4D; font-family: "Liberation Sans";' textLength='13.86px'
lengthAdjust='spacingAndGlyphs'>0%
</text>
<text x='230.18' y='239.51' text-anchor='middle'
style='font-size: 9.60px;fill: #4D4D4D; font-family: "Liberation Sans";' textLength='19.19px'
lengthAdjust='spacingAndGlyphs'>30%
</text>
<text x='352.43' y='239.51' text-anchor='middle'
style='font-size: 9.60px;fill: #4D4D4D; font-family: "Liberation Sans";' textLength='19.19px'
lengthAdjust='spacingAndGlyphs'>60%
</text>
<text x='474.67' y='239.51' text-anchor='middle'
style='font-size: 9.60px;fill: #4D4D4D; font-family: "Liberation Sans";' textLength='19.19px'
lengthAdjust='spacingAndGlyphs'>90%
</text>
<text x='327.98' y='252.74' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";'
textLength='50.67px' lengthAdjust='spacingAndGlyphs'>Pass rate
</text>
<rect x='273.74' y='273.94' width='15.73' height='15.73'
style='stroke-width: 1.16; stroke: none; stroke-linecap: butt; stroke-linejoin: miter; fill: #2CA02C;'/>
<rect x='333.88' y='273.94' width='15.73' height='15.73'
style='stroke-width: 1.16; stroke: none; stroke-linecap: butt; stroke-linejoin: miter; fill: #D62728;'/>
<text x='296.22' y='285.10' style='font-size: 9.60px; font-family: "Liberation Sans";' textLength='30.91px'
lengthAdjust='spacingAndGlyphs'>post-fix
</text>
<text x='356.37' y='285.10' style='font-size: 9.60px; font-family: "Liberation Sans";' textLength='26.62px'
lengthAdjust='spacingAndGlyphs'>pre-fix
</text>
<text x='85.94' y='33.10' style='font-size: 12.00px;fill: #505050; font-family: "Liberation Sans";'
textLength='387.47px' lengthAdjust='spacingAndGlyphs'>50 trials per run, unique random blocks across
the 22998-block data pool
</text>
<text x='85.94' y='15.88' style='font-size: 14.40px; font-weight: bold; font-family: "Liberation Sans";'
textLength='360.70px' lengthAdjust='spacingAndGlyphs'>Artemis surface stress test: pass rate
before/after fix
</text>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 7.8 KiB

@@ -0,0 +1,419 @@
<?xml version='1.0' encoding='UTF-8' ?>
<svg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' width='504.00pt' height='396.00pt'
viewBox='0 0 504.00 396.00'>
<g class='svglite'>
<defs>
<style type='text/css'><![CDATA[
.svglite line, .svglite polyline, .svglite polygon, .svglite path, .svglite rect, .svglite circle {
fill: none;
stroke: #000000;
stroke-linecap: round;
stroke-linejoin: round;
stroke-miterlimit: 10.00;
}
.svglite text {
white-space: pre;
}
.svglite g.glyphgroup path {
fill: inherit;
stroke: none;
}
]]></style>
</defs>
<rect width='100%' height='100%' style='stroke: none; fill: #FFFFFF;'/>
<defs>
<clipPath id='cpMC4wMHw1MDQuMDB8MC4wMHwzOTYuMDA='>
<rect x='0.00' y='0.00' width='504.00' height='396.00'/>
</clipPath>
</defs>
<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHwzOTYuMDA=)'>
<rect x='0.00' y='-0.00000000000011' width='504.00' height='396.00'
style='stroke-width: 1.16; stroke: none; fill: #FFFFFF;'/>
</g>
<defs>
<clipPath id='cpMzUuNzV8NDk4LjAyfDcyLjY4fDE4NC44NA=='>
<rect x='35.75' y='72.68' width='462.27' height='112.17'/>
</clipPath>
</defs>
<g clip-path='url(#cpMzUuNzV8NDk4LjAyfDcyLjY4fDE4NC44NA==)'>
<polyline points='35.75,179.74 498.02,179.74 '
style='stroke-width: 1.16; stroke: #EBEBEB; stroke-linecap: butt;'/>
<polyline points='35.75,158.93 498.02,158.93 '
style='stroke-width: 1.16; stroke: #EBEBEB; stroke-linecap: butt;'/>
<polyline points='35.75,138.12 498.02,138.12 '
style='stroke-width: 1.16; stroke: #EBEBEB; stroke-linecap: butt;'/>
<polyline points='35.75,117.31 498.02,117.31 '
style='stroke-width: 1.16; stroke: #EBEBEB; stroke-linecap: butt;'/>
<polyline points='35.75,96.50 498.02,96.50 '
style='stroke-width: 1.16; stroke: #EBEBEB; stroke-linecap: butt;'/>
<polyline points='35.75,75.69 498.02,75.69 '
style='stroke-width: 1.16; stroke: #EBEBEB; stroke-linecap: butt;'/>
<polyline points='90.93,184.84 90.93,72.68 '
style='stroke-width: 1.16; stroke: #EBEBEB; stroke-linecap: butt;'/>
<polyline points='183.20,184.84 183.20,72.68 '
style='stroke-width: 1.16; stroke: #EBEBEB; stroke-linecap: butt;'/>
<polyline points='275.48,184.84 275.48,72.68 '
style='stroke-width: 1.16; stroke: #EBEBEB; stroke-linecap: butt;'/>
<polyline points='367.75,184.84 367.75,72.68 '
style='stroke-width: 1.16; stroke: #EBEBEB; stroke-linecap: butt;'/>
<polyline points='460.03,184.84 460.03,72.68 '
style='stroke-width: 1.16; stroke: #EBEBEB; stroke-linecap: butt;'/>
<circle cx='207.30' cy='179.74' r='2.73'
style='stroke-width: 0.77; stroke: #2CA02C; stroke-opacity: 0.85; fill: #2CA02C; fill-opacity: 0.85;'/>
<circle cx='157.12' cy='177.66' r='2.73'
style='stroke-width: 0.77; stroke: #2CA02C; stroke-opacity: 0.85; fill: #2CA02C; fill-opacity: 0.85;'/>
<circle cx='56.76' cy='175.58' r='2.73'
style='stroke-width: 0.77; stroke: #2CA02C; stroke-opacity: 0.85; fill: #2CA02C; fill-opacity: 0.85;'/>
<circle cx='431.02' cy='173.50' r='2.73'
style='stroke-width: 0.77; stroke: #2CA02C; stroke-opacity: 0.85; fill: #2CA02C; fill-opacity: 0.85;'/>
<circle cx='380.84' cy='171.42' r='2.73'
style='stroke-width: 0.77; stroke: #2CA02C; stroke-opacity: 0.85; fill: #2CA02C; fill-opacity: 0.85;'/>
<circle cx='280.48' cy='169.34' r='2.73'
style='stroke-width: 0.77; stroke: #2CA02C; stroke-opacity: 0.85; fill: #2CA02C; fill-opacity: 0.85;'/>
<circle cx='230.30' cy='167.26' r='2.73'
style='stroke-width: 0.77; stroke: #2CA02C; stroke-opacity: 0.85; fill: #2CA02C; fill-opacity: 0.85;'/>
<circle cx='129.94' cy='165.18' r='2.73'
style='stroke-width: 0.77; stroke: #2CA02C; stroke-opacity: 0.85; fill: #2CA02C; fill-opacity: 0.85;'/>
<circle cx='79.76' cy='163.10' r='2.73'
style='stroke-width: 0.77; stroke: #2CA02C; stroke-opacity: 0.85; fill: #2CA02C; fill-opacity: 0.85;'/>
<circle cx='454.01' cy='161.01' r='2.73'
style='stroke-width: 0.77; stroke: #2CA02C; stroke-opacity: 0.85; fill: #2CA02C; fill-opacity: 0.85;'/>
<circle cx='403.83' cy='158.93' r='2.73'
style='stroke-width: 0.77; stroke: #2CA02C; stroke-opacity: 0.85; fill: #2CA02C; fill-opacity: 0.85;'/>
<circle cx='303.47' cy='156.85' r='2.73'
style='stroke-width: 0.77; stroke: #2CA02C; stroke-opacity: 0.85; fill: #2CA02C; fill-opacity: 0.85;'/>
<circle cx='477.01' cy='154.77' r='2.73'
style='stroke-width: 0.77; stroke: #2CA02C; stroke-opacity: 0.85; fill: #2CA02C; fill-opacity: 0.85;'/>
<circle cx='426.83' cy='152.69' r='2.73'
style='stroke-width: 0.77; stroke: #2CA02C; stroke-opacity: 0.85; fill: #2CA02C; fill-opacity: 0.85;'/>
<circle cx='376.65' cy='150.61' r='2.73'
style='stroke-width: 0.77; stroke: #2CA02C; stroke-opacity: 0.85; fill: #2CA02C; fill-opacity: 0.85;'/>
<circle cx='326.47' cy='148.53' r='2.73'
style='stroke-width: 0.77; stroke: #2CA02C; stroke-opacity: 0.85; fill: #2CA02C; fill-opacity: 0.85;'/>
<circle cx='226.11' cy='146.45' r='2.73'
style='stroke-width: 0.77; stroke: #2CA02C; stroke-opacity: 0.85; fill: #2CA02C; fill-opacity: 0.85;'/>
<circle cx='449.83' cy='144.37' r='2.73'
style='stroke-width: 0.77; stroke: #2CA02C; stroke-opacity: 0.85; fill: #2CA02C; fill-opacity: 0.85;'/>
<circle cx='399.65' cy='142.29' r='2.73'
style='stroke-width: 0.77; stroke: #2CA02C; stroke-opacity: 0.85; fill: #2CA02C; fill-opacity: 0.85;'/>
<circle cx='299.29' cy='140.20' r='2.73'
style='stroke-width: 0.77; stroke: #2CA02C; stroke-opacity: 0.85; fill: #2CA02C; fill-opacity: 0.85;'/>
<circle cx='249.11' cy='138.12' r='2.73'
style='stroke-width: 0.77; stroke: #2CA02C; stroke-opacity: 0.85; fill: #2CA02C; fill-opacity: 0.85;'/>
<circle cx='472.82' cy='136.04' r='2.73'
style='stroke-width: 0.77; stroke: #2CA02C; stroke-opacity: 0.85; fill: #2CA02C; fill-opacity: 0.85;'/>
<circle cx='422.64' cy='133.96' r='2.73'
style='stroke-width: 0.77; stroke: #2CA02C; stroke-opacity: 0.85; fill: #2CA02C; fill-opacity: 0.85;'/>
<circle cx='372.46' cy='131.88' r='2.73'
style='stroke-width: 0.77; stroke: #2CA02C; stroke-opacity: 0.85; fill: #2CA02C; fill-opacity: 0.85;'/>
<circle cx='322.28' cy='129.80' r='2.73'
style='stroke-width: 0.77; stroke: #2CA02C; stroke-opacity: 0.85; fill: #2CA02C; fill-opacity: 0.85;'/>
<circle cx='221.92' cy='127.72' r='2.73'
style='stroke-width: 0.77; stroke: #2CA02C; stroke-opacity: 0.85; fill: #2CA02C; fill-opacity: 0.85;'/>
<circle cx='71.38' cy='125.64' r='2.73'
style='stroke-width: 0.77; stroke: #2CA02C; stroke-opacity: 0.85; fill: #2CA02C; fill-opacity: 0.85;'/>
<circle cx='445.64' cy='123.56' r='2.73'
style='stroke-width: 0.77; stroke: #2CA02C; stroke-opacity: 0.85; fill: #2CA02C; fill-opacity: 0.85;'/>
<circle cx='395.46' cy='121.48' r='2.73'
style='stroke-width: 0.77; stroke: #2CA02C; stroke-opacity: 0.85; fill: #2CA02C; fill-opacity: 0.85;'/>
<circle cx='295.10' cy='119.40' r='2.73'
style='stroke-width: 0.77; stroke: #2CA02C; stroke-opacity: 0.85; fill: #2CA02C; fill-opacity: 0.85;'/>
<circle cx='244.92' cy='117.31' r='2.73'
style='stroke-width: 0.77; stroke: #2CA02C; stroke-opacity: 0.85; fill: #2CA02C; fill-opacity: 0.85;'/>
<circle cx='94.38' cy='115.23' r='2.73'
style='stroke-width: 0.77; stroke: #2CA02C; stroke-opacity: 0.85; fill: #2CA02C; fill-opacity: 0.85;'/>
<circle cx='468.63' cy='113.15' r='2.73'
style='stroke-width: 0.77; stroke: #2CA02C; stroke-opacity: 0.85; fill: #2CA02C; fill-opacity: 0.85;'/>
<circle cx='418.45' cy='111.07' r='2.73'
style='stroke-width: 0.77; stroke: #2CA02C; stroke-opacity: 0.85; fill: #2CA02C; fill-opacity: 0.85;'/>
<circle cx='368.27' cy='108.99' r='2.73'
style='stroke-width: 0.77; stroke: #2CA02C; stroke-opacity: 0.85; fill: #2CA02C; fill-opacity: 0.85;'/>
<circle cx='217.73' cy='106.91' r='2.73'
style='stroke-width: 0.77; stroke: #2CA02C; stroke-opacity: 0.85; fill: #2CA02C; fill-opacity: 0.85;'/>
<circle cx='441.45' cy='104.83' r='2.73'
style='stroke-width: 0.77; stroke: #2CA02C; stroke-opacity: 0.85; fill: #2CA02C; fill-opacity: 0.85;'/>
<circle cx='391.27' cy='102.75' r='2.73'
style='stroke-width: 0.77; stroke: #2CA02C; stroke-opacity: 0.85; fill: #2CA02C; fill-opacity: 0.85;'/>
<circle cx='240.73' cy='100.67' r='2.73'
style='stroke-width: 0.77; stroke: #2CA02C; stroke-opacity: 0.85; fill: #2CA02C; fill-opacity: 0.85;'/>
<circle cx='464.44' cy='98.59' r='2.73'
style='stroke-width: 0.77; stroke: #2CA02C; stroke-opacity: 0.85; fill: #2CA02C; fill-opacity: 0.85;'/>
<circle cx='414.26' cy='96.50' r='2.73'
style='stroke-width: 0.77; stroke: #2CA02C; stroke-opacity: 0.85; fill: #2CA02C; fill-opacity: 0.85;'/>
<circle cx='364.08' cy='94.42' r='2.73'
style='stroke-width: 0.77; stroke: #2CA02C; stroke-opacity: 0.85; fill: #2CA02C; fill-opacity: 0.85;'/>
<circle cx='313.90' cy='92.34' r='2.73'
style='stroke-width: 0.77; stroke: #2CA02C; stroke-opacity: 0.85; fill: #2CA02C; fill-opacity: 0.85;'/>
<circle cx='263.72' cy='90.26' r='2.73'
style='stroke-width: 0.77; stroke: #2CA02C; stroke-opacity: 0.85; fill: #2CA02C; fill-opacity: 0.85;'/>
<circle cx='437.26' cy='88.18' r='2.73'
style='stroke-width: 0.77; stroke: #2CA02C; stroke-opacity: 0.85; fill: #2CA02C; fill-opacity: 0.85;'/>
<circle cx='387.08' cy='86.10' r='2.73'
style='stroke-width: 0.77; stroke: #2CA02C; stroke-opacity: 0.85; fill: #2CA02C; fill-opacity: 0.85;'/>
<circle cx='336.90' cy='84.02' r='2.73'
style='stroke-width: 0.77; stroke: #2CA02C; stroke-opacity: 0.85; fill: #2CA02C; fill-opacity: 0.85;'/>
<circle cx='236.54' cy='81.94' r='2.73'
style='stroke-width: 0.77; stroke: #2CA02C; stroke-opacity: 0.85; fill: #2CA02C; fill-opacity: 0.85;'/>
<circle cx='86.00' cy='79.86' r='2.73'
style='stroke-width: 0.77; stroke: #2CA02C; stroke-opacity: 0.85; fill: #2CA02C; fill-opacity: 0.85;'/>
<circle cx='460.25' cy='77.78' r='2.73'
style='stroke-width: 0.77; stroke: #2CA02C; stroke-opacity: 0.85; fill: #2CA02C; fill-opacity: 0.85;'/>
</g>
<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHwzOTYuMDA=)'>
</g>
<defs>
<clipPath id='cpMzUuNzV8NDk4LjAyfDIwOC45N3wzMjEuMTM='>
<rect x='35.75' y='208.97' width='462.27' height='112.17'/>
</clipPath>
</defs>
<g clip-path='url(#cpMzUuNzV8NDk4LjAyfDIwOC45N3wzMjEuMTM=)'>
<polyline points='35.75,316.03 498.02,316.03 '
style='stroke-width: 1.16; stroke: #EBEBEB; stroke-linecap: butt;'/>
<polyline points='35.75,295.22 498.02,295.22 '
style='stroke-width: 1.16; stroke: #EBEBEB; stroke-linecap: butt;'/>
<polyline points='35.75,274.41 498.02,274.41 '
style='stroke-width: 1.16; stroke: #EBEBEB; stroke-linecap: butt;'/>
<polyline points='35.75,253.60 498.02,253.60 '
style='stroke-width: 1.16; stroke: #EBEBEB; stroke-linecap: butt;'/>
<polyline points='35.75,232.79 498.02,232.79 '
style='stroke-width: 1.16; stroke: #EBEBEB; stroke-linecap: butt;'/>
<polyline points='35.75,211.98 498.02,211.98 '
style='stroke-width: 1.16; stroke: #EBEBEB; stroke-linecap: butt;'/>
<polyline points='90.93,321.13 90.93,208.97 '
style='stroke-width: 1.16; stroke: #EBEBEB; stroke-linecap: butt;'/>
<polyline points='183.20,321.13 183.20,208.97 '
style='stroke-width: 1.16; stroke: #EBEBEB; stroke-linecap: butt;'/>
<polyline points='275.48,321.13 275.48,208.97 '
style='stroke-width: 1.16; stroke: #EBEBEB; stroke-linecap: butt;'/>
<polyline points='367.75,321.13 367.75,208.97 '
style='stroke-width: 1.16; stroke: #EBEBEB; stroke-linecap: butt;'/>
<polyline points='460.03,321.13 460.03,208.97 '
style='stroke-width: 1.16; stroke: #EBEBEB; stroke-linecap: butt;'/>
<circle cx='207.30' cy='316.03' r='2.73'
style='stroke-width: 0.77; stroke: #D62728; stroke-opacity: 0.85; fill: #D62728; fill-opacity: 0.85;'/>
<circle cx='157.12' cy='313.95' r='2.73'
style='stroke-width: 0.77; stroke: #D62728; stroke-opacity: 0.85; fill: #D62728; fill-opacity: 0.85;'/>
<circle cx='56.76' cy='311.87' r='2.73'
style='stroke-width: 0.77; stroke: #D62728; stroke-opacity: 0.85; fill: #D62728; fill-opacity: 0.85;'/>
<circle cx='380.84' cy='309.79' r='2.73'
style='stroke-width: 0.77; stroke: #2CA02C; stroke-opacity: 0.85; fill: #2CA02C; fill-opacity: 0.85;'/>
<circle cx='280.48' cy='307.71' r='2.73'
style='stroke-width: 0.77; stroke: #2CA02C; stroke-opacity: 0.85; fill: #2CA02C; fill-opacity: 0.85;'/>
<circle cx='230.30' cy='305.63' r='2.73'
style='stroke-width: 0.77; stroke: #D62728; stroke-opacity: 0.85; fill: #D62728; fill-opacity: 0.85;'/>
<circle cx='180.12' cy='303.55' r='2.73'
style='stroke-width: 0.77; stroke: #2CA02C; stroke-opacity: 0.85; fill: #2CA02C; fill-opacity: 0.85;'/>
<circle cx='129.94' cy='301.47' r='2.73'
style='stroke-width: 0.77; stroke: #2CA02C; stroke-opacity: 0.85; fill: #2CA02C; fill-opacity: 0.85;'/>
<circle cx='79.76' cy='299.39' r='2.73'
style='stroke-width: 0.77; stroke: #D62728; stroke-opacity: 0.85; fill: #D62728; fill-opacity: 0.85;'/>
<circle cx='454.01' cy='297.30' r='2.73'
style='stroke-width: 0.77; stroke: #D62728; stroke-opacity: 0.85; fill: #D62728; fill-opacity: 0.85;'/>
<circle cx='403.83' cy='295.22' r='2.73'
style='stroke-width: 0.77; stroke: #2CA02C; stroke-opacity: 0.85; fill: #2CA02C; fill-opacity: 0.85;'/>
<circle cx='303.47' cy='293.14' r='2.73'
style='stroke-width: 0.77; stroke: #D62728; stroke-opacity: 0.85; fill: #D62728; fill-opacity: 0.85;'/>
<circle cx='102.75' cy='291.06' r='2.73'
style='stroke-width: 0.77; stroke: #2CA02C; stroke-opacity: 0.85; fill: #2CA02C; fill-opacity: 0.85;'/>
<circle cx='477.01' cy='288.98' r='2.73'
style='stroke-width: 0.77; stroke: #2CA02C; stroke-opacity: 0.85; fill: #2CA02C; fill-opacity: 0.85;'/>
<circle cx='426.83' cy='286.90' r='2.73'
style='stroke-width: 0.77; stroke: #2CA02C; stroke-opacity: 0.85; fill: #2CA02C; fill-opacity: 0.85;'/>
<circle cx='376.65' cy='284.82' r='2.73'
style='stroke-width: 0.77; stroke: #2CA02C; stroke-opacity: 0.85; fill: #2CA02C; fill-opacity: 0.85;'/>
<circle cx='326.47' cy='282.74' r='2.73'
style='stroke-width: 0.77; stroke: #2CA02C; stroke-opacity: 0.85; fill: #2CA02C; fill-opacity: 0.85;'/>
<circle cx='226.11' cy='280.66' r='2.73'
style='stroke-width: 0.77; stroke: #D62728; stroke-opacity: 0.85; fill: #D62728; fill-opacity: 0.85;'/>
<circle cx='399.65' cy='278.58' r='2.73'
style='stroke-width: 0.77; stroke: #D62728; stroke-opacity: 0.85; fill: #D62728; fill-opacity: 0.85;'/>
<circle cx='299.29' cy='276.49' r='2.73'
style='stroke-width: 0.77; stroke: #2CA02C; stroke-opacity: 0.85; fill: #2CA02C; fill-opacity: 0.85;'/>
<circle cx='249.11' cy='274.41' r='2.73'
style='stroke-width: 0.77; stroke: #D62728; stroke-opacity: 0.85; fill: #D62728; fill-opacity: 0.85;'/>
<circle cx='148.75' cy='272.33' r='2.73'
style='stroke-width: 0.77; stroke: #D62728; stroke-opacity: 0.85; fill: #D62728; fill-opacity: 0.85;'/>
<circle cx='472.82' cy='270.25' r='2.73'
style='stroke-width: 0.77; stroke: #2CA02C; stroke-opacity: 0.85; fill: #2CA02C; fill-opacity: 0.85;'/>
<circle cx='322.28' cy='268.17' r='2.73'
style='stroke-width: 0.77; stroke: #2CA02C; stroke-opacity: 0.85; fill: #2CA02C; fill-opacity: 0.85;'/>
<circle cx='221.92' cy='266.09' r='2.73'
style='stroke-width: 0.77; stroke: #D62728; stroke-opacity: 0.85; fill: #D62728; fill-opacity: 0.85;'/>
<circle cx='171.74' cy='264.01' r='2.73'
style='stroke-width: 0.77; stroke: #D62728; stroke-opacity: 0.85; fill: #D62728; fill-opacity: 0.85;'/>
<circle cx='71.38' cy='261.93' r='2.73'
style='stroke-width: 0.77; stroke: #D62728; stroke-opacity: 0.85; fill: #D62728; fill-opacity: 0.85;'/>
<circle cx='395.46' cy='259.85' r='2.73'
style='stroke-width: 0.77; stroke: #2CA02C; stroke-opacity: 0.85; fill: #2CA02C; fill-opacity: 0.85;'/>
<circle cx='295.10' cy='257.77' r='2.73'
style='stroke-width: 0.77; stroke: #2CA02C; stroke-opacity: 0.85; fill: #2CA02C; fill-opacity: 0.85;'/>
<circle cx='244.92' cy='255.68' r='2.73'
style='stroke-width: 0.77; stroke: #D62728; stroke-opacity: 0.85; fill: #D62728; fill-opacity: 0.85;'/>
<circle cx='144.56' cy='253.60' r='2.73'
style='stroke-width: 0.77; stroke: #D62728; stroke-opacity: 0.85; fill: #D62728; fill-opacity: 0.85;'/>
<circle cx='94.38' cy='251.52' r='2.73'
style='stroke-width: 0.77; stroke: #D62728; stroke-opacity: 0.85; fill: #D62728; fill-opacity: 0.85;'/>
<circle cx='468.63' cy='249.44' r='2.73'
style='stroke-width: 0.77; stroke: #2CA02C; stroke-opacity: 0.85; fill: #2CA02C; fill-opacity: 0.85;'/>
<circle cx='418.45' cy='247.36' r='2.73'
style='stroke-width: 0.77; stroke: #D62728; stroke-opacity: 0.85; fill: #D62728; fill-opacity: 0.85;'/>
<circle cx='217.73' cy='245.28' r='2.73'
style='stroke-width: 0.77; stroke: #D62728; stroke-opacity: 0.85; fill: #D62728; fill-opacity: 0.85;'/>
<circle cx='67.19' cy='243.20' r='2.73'
style='stroke-width: 0.77; stroke: #D62728; stroke-opacity: 0.85; fill: #D62728; fill-opacity: 0.85;'/>
<circle cx='441.45' cy='241.12' r='2.73'
style='stroke-width: 0.77; stroke: #2CA02C; stroke-opacity: 0.85; fill: #2CA02C; fill-opacity: 0.85;'/>
<circle cx='391.27' cy='239.04' r='2.73'
style='stroke-width: 0.77; stroke: #2CA02C; stroke-opacity: 0.85; fill: #2CA02C; fill-opacity: 0.85;'/>
<circle cx='240.73' cy='236.96' r='2.73'
style='stroke-width: 0.77; stroke: #D62728; stroke-opacity: 0.85; fill: #D62728; fill-opacity: 0.85;'/>
<circle cx='414.26' cy='234.87' r='2.73'
style='stroke-width: 0.77; stroke: #2CA02C; stroke-opacity: 0.85; fill: #2CA02C; fill-opacity: 0.85;'/>
<circle cx='364.08' cy='232.79' r='2.73'
style='stroke-width: 0.77; stroke: #D62728; stroke-opacity: 0.85; fill: #D62728; fill-opacity: 0.85;'/>
<circle cx='313.90' cy='230.71' r='2.73'
style='stroke-width: 0.77; stroke: #2CA02C; stroke-opacity: 0.85; fill: #2CA02C; fill-opacity: 0.85;'/>
<circle cx='263.72' cy='228.63' r='2.73'
style='stroke-width: 0.77; stroke: #2CA02C; stroke-opacity: 0.85; fill: #2CA02C; fill-opacity: 0.85;'/>
<circle cx='163.36' cy='226.55' r='2.73'
style='stroke-width: 0.77; stroke: #D62728; stroke-opacity: 0.85; fill: #D62728; fill-opacity: 0.85;'/>
<circle cx='336.90' cy='224.47' r='2.73'
style='stroke-width: 0.77; stroke: #2CA02C; stroke-opacity: 0.85; fill: #2CA02C; fill-opacity: 0.85;'/>
<circle cx='236.54' cy='222.39' r='2.73'
style='stroke-width: 0.77; stroke: #2CA02C; stroke-opacity: 0.85; fill: #2CA02C; fill-opacity: 0.85;'/>
<circle cx='186.36' cy='220.31' r='2.73'
style='stroke-width: 0.77; stroke: #D62728; stroke-opacity: 0.85; fill: #D62728; fill-opacity: 0.85;'/>
<circle cx='86.00' cy='218.23' r='2.73'
style='stroke-width: 0.77; stroke: #D62728; stroke-opacity: 0.85; fill: #D62728; fill-opacity: 0.85;'/>
<circle cx='410.07' cy='216.15' r='2.73'
style='stroke-width: 0.77; stroke: #2CA02C; stroke-opacity: 0.85; fill: #2CA02C; fill-opacity: 0.85;'/>
<circle cx='309.71' cy='214.06' r='2.73'
style='stroke-width: 0.77; stroke: #2CA02C; stroke-opacity: 0.85; fill: #2CA02C; fill-opacity: 0.85;'/>
</g>
<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHwzOTYuMDA=)'>
</g>
<defs>
<clipPath id='cpMzUuNzV8NDk4LjAyfDE5MC44MnwyMDguOTc='>
<rect x='35.75' y='190.82' width='462.27' height='18.15'/>
</clipPath>
</defs>
<g clip-path='url(#cpMzUuNzV8NDk4LjAyfDE5MC44MnwyMDguOTc=)'>
<text x='266.89' y='203.19' text-anchor='middle'
style='font-size: 9.60px;fill: #1A1A1A; font-family: "Liberation Sans";' textLength='64.97px'
lengthAdjust='spacingAndGlyphs'>amd64 (pre-fix)
</text>
</g>
<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHwzOTYuMDA=)'>
</g>
<defs>
<clipPath id='cpMzUuNzV8NDk4LjAyfDU0LjUzfDcyLjY4'>
<rect x='35.75' y='54.53' width='462.27' height='18.15'/>
</clipPath>
</defs>
<g clip-path='url(#cpMzUuNzV8NDk4LjAyfDU0LjUzfDcyLjY4)'>
<text x='266.89' y='66.90' text-anchor='middle'
style='font-size: 9.60px;fill: #1A1A1A; font-family: "Liberation Sans";' textLength='69.25px'
lengthAdjust='spacingAndGlyphs'>amd64 (post-fix)
</text>
</g>
<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHwzOTYuMDA=)'>
<text x='90.93' y='333.11' text-anchor='middle'
style='font-size: 9.60px;fill: #4D4D4D; font-family: "Liberation Sans";' textLength='21.31px'
lengthAdjust='spacingAndGlyphs'>5000
</text>
<text x='183.20' y='333.11' text-anchor='middle'
style='font-size: 9.60px;fill: #4D4D4D; font-family: "Liberation Sans";' textLength='26.64px'
lengthAdjust='spacingAndGlyphs'>10000
</text>
<text x='275.48' y='333.11' text-anchor='middle'
style='font-size: 9.60px;fill: #4D4D4D; font-family: "Liberation Sans";' textLength='26.64px'
lengthAdjust='spacingAndGlyphs'>15000
</text>
<text x='367.75' y='333.11' text-anchor='middle'
style='font-size: 9.60px;fill: #4D4D4D; font-family: "Liberation Sans";' textLength='26.64px'
lengthAdjust='spacingAndGlyphs'>20000
</text>
<text x='460.03' y='333.11' text-anchor='middle'
style='font-size: 9.60px;fill: #4D4D4D; font-family: "Liberation Sans";' textLength='26.64px'
lengthAdjust='spacingAndGlyphs'>25000
</text>
<text x='30.37' y='183.04' text-anchor='end'
style='font-size: 9.60px;fill: #4D4D4D; font-family: "Liberation Sans";' textLength='5.33px'
lengthAdjust='spacingAndGlyphs'>0
</text>
<text x='30.37' y='162.23' text-anchor='end'
style='font-size: 9.60px;fill: #4D4D4D; font-family: "Liberation Sans";' textLength='10.66px'
lengthAdjust='spacingAndGlyphs'>10
</text>
<text x='30.37' y='141.42' text-anchor='end'
style='font-size: 9.60px;fill: #4D4D4D; font-family: "Liberation Sans";' textLength='10.66px'
lengthAdjust='spacingAndGlyphs'>20
</text>
<text x='30.37' y='120.61' text-anchor='end'
style='font-size: 9.60px;fill: #4D4D4D; font-family: "Liberation Sans";' textLength='10.66px'
lengthAdjust='spacingAndGlyphs'>30
</text>
<text x='30.37' y='99.80' text-anchor='end'
style='font-size: 9.60px;fill: #4D4D4D; font-family: "Liberation Sans";' textLength='10.66px'
lengthAdjust='spacingAndGlyphs'>40
</text>
<text x='30.37' y='78.99' text-anchor='end'
style='font-size: 9.60px;fill: #4D4D4D; font-family: "Liberation Sans";' textLength='10.66px'
lengthAdjust='spacingAndGlyphs'>50
</text>
<text x='30.37' y='319.33' text-anchor='end'
style='font-size: 9.60px;fill: #4D4D4D; font-family: "Liberation Sans";' textLength='5.33px'
lengthAdjust='spacingAndGlyphs'>0
</text>
<text x='30.37' y='298.52' text-anchor='end'
style='font-size: 9.60px;fill: #4D4D4D; font-family: "Liberation Sans";' textLength='10.66px'
lengthAdjust='spacingAndGlyphs'>10
</text>
<text x='30.37' y='277.71' text-anchor='end'
style='font-size: 9.60px;fill: #4D4D4D; font-family: "Liberation Sans";' textLength='10.66px'
lengthAdjust='spacingAndGlyphs'>20
</text>
<text x='30.37' y='256.90' text-anchor='end'
style='font-size: 9.60px;fill: #4D4D4D; font-family: "Liberation Sans";' textLength='10.66px'
lengthAdjust='spacingAndGlyphs'>30
</text>
<text x='30.37' y='236.09' text-anchor='end'
style='font-size: 9.60px;fill: #4D4D4D; font-family: "Liberation Sans";' textLength='10.66px'
lengthAdjust='spacingAndGlyphs'>40
</text>
<text x='30.37' y='215.28' text-anchor='end'
style='font-size: 9.60px;fill: #4D4D4D; font-family: "Liberation Sans";' textLength='10.66px'
lengthAdjust='spacingAndGlyphs'>50
</text>
<text x='266.89' y='346.34' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";'
textLength='244.78px' lengthAdjust='spacingAndGlyphs'>Logical block number (data pool: 3076-26073)
</text>
<text transform='translate(14.24,196.90) rotate(-90)' text-anchor='middle'
style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='54.92px'
lengthAdjust='spacingAndGlyphs'>Trial index
</text>
<circle cx='226.96' cy='375.40' r='2.73'
style='stroke-width: 0.77; stroke: #2CA02C; stroke-opacity: 0.85; fill: #2CA02C; fill-opacity: 0.85;'/>
<circle cx='281.10' cy='375.40' r='2.73'
style='stroke-width: 0.77; stroke: #D62728; stroke-opacity: 0.85; fill: #D62728; fill-opacity: 0.85;'/>
<text x='241.58' y='378.70' style='font-size: 9.60px; font-family: "Liberation Sans";' textLength='24.91px'
lengthAdjust='spacingAndGlyphs'>PASS
</text>
<text x='295.72' y='378.70' style='font-size: 9.60px; font-family: "Liberation Sans";' textLength='19.73px'
lengthAdjust='spacingAndGlyphs'>FAIL
</text>
<text x='35.75' y='33.10' style='font-size: 12.00px;fill: #505050; font-family: "Liberation Sans";'
textLength='347.72px' lengthAdjust='spacingAndGlyphs'>Each point is one trial's block. A Wilcoxon test
(H2) finds LBN and
</text>
<text x='35.75' y='46.06' style='font-size: 12.00px;fill: #505050; font-family: "Liberation Sans";'
textLength='368.14px' lengthAdjust='spacingAndGlyphs'>outcome are not independent, but no sub-region
is visually implicated
</text>
<text x='35.75' y='15.88' style='font-size: 14.40px; font-weight: bold; font-family: "Liberation Sans";'
textLength='362.31px' lengthAdjust='spacingAndGlyphs'>Surface coverage: scattered across the full data
pool
</text>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 133 KiB

@@ -0,0 +1,7 @@
*.aux
*.log
*.out
*.toc
*.synctex.gz
*.fls
*.fdb_latexmk
@@ -0,0 +1,388 @@
\documentclass[10pt,a4paper]{article}
%% ── Packages ─────────────────────────────────────────────────────────────
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage[margin=2.5cm]{geometry}
\usepackage{graphicx}
\usepackage{booktabs}
\usepackage{amsmath}
\usepackage{amssymb}
\usepackage{xcolor}
\usepackage{microtype}
\usepackage{parskip}
\usepackage{enumitem}
\usepackage[hidelinks,colorlinks=true,linkcolor=black,citecolor=black,urlcolor=blue]{hyperref}
\usepackage{lmodern}
\usepackage{colortbl}
\usepackage{listings}
%% ── Colour palette (matches experiments/bare_metal house style) ─────────
\definecolor{sfblue}{RGB}{31,119,180}
\definecolor{sforange}{RGB}{255,127,14}
\definecolor{sfgreen}{RGB}{44,160,44}
\definecolor{sfred}{RGB}{214,39,40}
\definecolor{sfgray}{RGB}{80,80,80}
\lstset{
basicstyle=\ttfamily\small,
breaklines=true,
frame=single,
columns=fullflexible,
backgroundcolor=\color{black!3}
}
%% ── Figure path ───────────────────────────────────────────────────────────
\graphicspath{{figures/}}
%% ── Title metadata ────────────────────────────────────────────────────────
\title{%
\textbf{The Artemis Surface Stress Test}\\[0.4em]
\large A Stale-Pointer Aliasing Bug in the LithosAnanke Block Subsystem\\[0.3em]
\normalsize\textit{Found, Diagnosed, Fixed, and Verified Across Three Instruction-Set Architectures}
}
\author{%
R.\,A. James (Captain Bob)\\[0.2em]
\small StarForth Project \quad\texttt{robert.allan.james@gmail.com}
}
\date{2 August 2026}
%% ═══════════════════════════════════════════════════════════════════════
\begin{document}
\maketitle
\thispagestyle{empty}
\begin{abstract}
\noindent
A newly written stress test for Artemis, LithosAnanke's block-storage VM,
found a real data-corruption bug on its first completed run: 25 of 50
random-block write/verify trials (50\%) returned the wrong byte pattern on
amd64. The test's own recorded data ruled out its block-selection logic as
the cause (no duplicate logical block numbers or devblocks among the 50
trials). Four exploratory hypotheses were then tested formally rather than
read off a chart: a Wald--Wolfowitz runs test found no significant serial
clustering of failures by write order ($p=1.00$); a direct rank test
against write order agreed ($p=0.715$); sibling position within a shared
4\,KiB devblock showed no association ($p=0.674$); but logical block
number itself showed a significant association with outcome
($p<0.001$, Wilcoxon), an effect specific to this run's fixed random seed
that this report does not claim generalizes. None of these exploratory
tests, on their own, identify a mechanism. Root cause was instead found by
source code review: a stale raw-pointer alias held by the VM-level block
window cache (\texttt{src/word\_source/block\_words.c}) into a slot of the
block-subsystem's own eight-entry devblock cache
(\texttt{src/block\_subsystem.c}), which the subsystem's own FIFO eviction
relocates via struct-copy without informing the window cache holding a
pointer into it. No prior test had ever touched enough distinct blocks in
one VM session to trigger it, and the defect is independent of unrelated
same-day work on Artemis's disk-format detection. A three-site fix --
re-resolving the buffer pointer by logical block number immediately before
every write-through-cache-pointer operation, rather than trusting a
pointer captured earlier -- eliminates the defect without altering the
block subsystem's cache architecture. This is confirmed by the strongest
result in this report: a two-proportion test of pre-fix versus pooled
post-fix (three architectures, 150 trials) pass rate rejects the null
hypothesis of no change at $p = 2.04\times10^{-19}$. Re-verification:
50/50 on amd64, 50/50 on aarch64, 50/50 on riscv64, zero mismatches. The
test itself is now a permanent, on-demand fixture in the Artemis capsule
(\texttt{ART-STRESS} / \texttt{ART-STRESS-TEST}), disabled by default so
it does not add to ordinary boot time.
\end{abstract}
\section{Motivation}
Prior to this investigation, every automated exercise of Artemis's
block-storage path -- \texttt{ART-WRITE-TEST}, \texttt{ART-READ-TEST},
\texttt{ART-SELF-TEST} -- touched exactly one data block per run. That is
sufficient to prove the alloc/persist/free lifecycle works in isolation,
but it never puts real pressure on the underlying caches: the
block-subsystem's own eight-slot devblock cache
(\texttt{DISK\_CACHE\_SLOTS} in \texttt{block\_subsystem.c}) and the
VM-level ``window'' cache used by the \texttt{BLOCK}/\texttt{BUFFER}/
\texttt{UPDATE} words (\texttt{block\_words.c}) were never both forced to
evict within a single VM session.
The request behind this work was explicit: give the mounted virtual disk
a real workout -- real FORTH doing real writes, scattered randomly across
its entire surface area, on the premise that a test never exercised
before was the most likely place to find a crack.
\section{Test Design}
\texttt{ART-STRESS-TEST~( seed reps -- )} performs a two-phase write/verify
cycle against \texttt{reps} distinct, randomly chosen blocks drawn from the
full 22\,998-block Artemis data pool (logical block numbers 3076--26073):
\begin{enumerate}[nosep]
\item \textbf{Pick.} A coprime-stride walk over the index space
(stride and starting offset both drawn via \texttt{RANDOM}, stride
forced odd and checked against the two odd prime factors of 22\,998 =
$2 \times 3 \times 3833$) selects a block index guaranteed not to repeat
within the run, skipping past any index already allocated by something
else so the test never overwrites pre-existing legitimate data.
\item \textbf{Write.} The block is allocated through the same path
\texttt{BLK-ALLOC} uses internally (free-map bit set, heat born hot),
filled with a trial-derived byte pattern, and persisted.
\item \textbf{Verify.} After \emph{all} \texttt{reps} writes complete --
forcing real eviction/reload traffic through both cache layers -- each
block is re-fetched and its content checked against what was written.
\item \textbf{Record.} Every trial, pass or fail, emits one
\texttt{[ARTSTRESS]}-tagged CSV row (trial, logical block number,
pattern, result) to the serial log, plus a \texttt{HEADER} marker at
start and a \texttt{SUMMARY} marker at completion -- if a run is
killed mid-way, the summary marker is simply absent, making a
truncated dataset unmistakable rather than silently partial.
\item \textbf{Clean up.} Every block the run allocated is freed.
\end{enumerate}
The design deliberately treats this as an offline data-collection fixture,
the same posture as the existing DoE campaign: correctness of the
collected data matters more than run speed, and \texttt{ART-K-TOTAL} is
recorded before and after (informational only -- it is not a pass/fail
gate, since a background heartbeat decay tick during a long run is
expected behavior, not a defect).
The first completed run, 50 trials on amd64 with seed 424242 (the fixed
seed \texttt{ART-STRESS} uses), returned \textbf{25 passes and 25
failures} -- an exact 50\% split (Figure~\ref{fig:pass-rate}, bottom bar).
\begin{figure}[htb]
\centering
\includegraphics[width=0.8\linewidth]{pass_rate_comparison.pdf}
\caption{Pass rate per run. The pre-fix amd64 run is the only failure;
every post-fix run, on all three architectures, is 50/50.}
\label{fig:pass-rate}
\end{figure}
\section{Statistical Analysis}
\textbf{Premise.} A 50\% failure rate on the first completed run of a new
test is consistent with at least three distinct explanations, which are
not mutually exclusive: (a) a bug in the test's own block-selection logic
producing duplicate or colliding picks, (b) a genuine but narrow defect
tied to a specific access pattern (e.g.\ cache eviction timing), or (c) a
defect tied to a specific region of the disk. Duplicate logical block
numbers and duplicate devblocks among the 50 trials were checked directly
against the recorded data and neither was found, ruling out (a) as stated.
The hypotheses below were formulated to distinguish (b) from (c) before
committing to a source-code investigation in either direction.
All tests below use the pre-fix amd64 run's own recorded trial data
(\texttt{runs/amd64\_buggy.csv}, $n=50$, under
\texttt{experiments/artemis\_stress/}) and were computed by the analysis
script \texttt{analyse\_artemis\_stress.R} in that same directory; no
number in this section is hand-typed.
\begin{table}[htb]
\centering
\small
\begin{tabular}{p{0.28\linewidth}p{0.42\linewidth}p{0.22\linewidth}}
\toprule
Hypothesis & Null hypothesis ($H_0$) & Result \\
\midrule
H1 -- serial clustering &
Pass/fail outcomes are independently ordered (Wald--Wolfowitz runs test) &
26 runs observed, 26.0 expected; $z=0.000$, $p=1.00$ -- \textbf{fail to reject} \\
H1b -- write-order rank &
Trial index distribution is the same for PASS and FAIL (Wilcoxon) &
$W=332.0$, $p=0.715$ -- \textbf{fail to reject} \\
H2 -- disk location &
LBN distribution is the same for PASS and FAIL (Wilcoxon) &
$W=505.0$, $p<0.001$ -- \textbf{reject} \\
H2b -- sibling position &
Outcome independent of position (0/1/2) within a devblock ($\chi^2$) &
$\chi^2=0.790$, $\mathrm{df}=2$, $p=0.674$ -- \textbf{fail to reject} \\
H3 -- fix efficacy &
Pre-fix and post-fix trials share the same true pass rate (two-proportion test) &
$\chi^2=81.20$, $\mathrm{df}=1$, $p=2.04\times10^{-19}$ -- \textbf{reject} \\
\bottomrule
\end{tabular}
\caption{Hypothesis tests against the recorded trial data. $\alpha = 0.05$
throughout.}
\label{tab:hypotheses}
\end{table}
\textbf{H1 and H1b -- no evidence of write-order clustering.} A visual
scan of the pass/fail sequence in write order
(Figure~\ref{fig:sequence}) initially suggested runs of consecutive
failures -- trials 24, 25, 26 failing together, then 27 and 28 passing,
then 29, 30, 31 failing again. A formal runs test does not support that
reading: 26 runs were observed against 26.0 expected under a purely
random ordering with the same 25/25 split ($z=0.000$). A direct Wilcoxon
test of trial index by outcome agrees ($p=0.715$). \textbf{The naive
``recently written survives, long ago fails'' cache-timing story is not
supported by this data} and should not be asserted as the mechanism.
\begin{figure}[htb]
\centering
\includegraphics[width=0.95\linewidth]{failure_clustering.pdf}
\caption{Pass/fail by trial order, amd64 pre-fix run. Visually
suggestive of clustering; not statistically confirmed (H1, H1b).}
\label{fig:sequence}
\end{figure}
\textbf{H2 and H2b -- an unresolved location effect, specific to this
seed.} Logical block number \emph{does} show a significant association
with outcome ($p<0.001$): failing trials in this run had a lower mean LBN
($\bar{x} \approx 11{,}355$) than passing trials ($\bar{x} \approx
18{,}401$). This was not expected, and this report does not have a causal
explanation for it -- the diagnosed mechanism (Section~\ref{sec:rootcause})
is a pointer-aliasing defect tied to cache eviction \emph{order}, and
this section's H1/H1b results (above) show no association with order in
this run, which is in tension with a simple location-driven story. The most defensible
reading is that \texttt{ART-STRESS-TEST}'s seed (424242) is fixed, so the
specific sequence of devblock accesses -- and therefore which window-cache
pointers go stale -- is a deterministic, reproducible function of that
seed for this run, and some property of that one sequence happens to
correlate with LBN value without implying that block number is, in
general, a causal factor. Sibling position within a shared devblock shows
no association ($p=0.674$), which rules out the simplest region-based
explanation (three data blocks per 4\,KiB devblock, checked directly).
This finding is reported rather than smoothed over; it does not change
the fix or its verification, and Figure~\ref{fig:coverage}'s lower panel
shows no visually obvious sub-region concentration despite the test
result.
\begin{figure}[htb]
\centering
\includegraphics[width=0.85\linewidth]{surface_coverage_map.pdf}
\caption{Every trial's logical block number against trial order,
amd64. Upper panel: post-fix, all passing. Lower panel: pre-fix.}
\label{fig:coverage}
\end{figure}
\textbf{Conclusion of this section.} None of H1, H1b, or H2/H2b, singly
or together, identify a mechanism -- they narrow the search (ruling out
write-order clustering and sibling-position effects as the story) without
answering the question. Root cause was found by source code review,
described next; H3, in Section~\ref{sec:verification}, is what actually
confirms the diagnosis, by showing the identified defect's fix removes
the failures entirely and unambiguously.
\section{Root Cause}
\label{sec:rootcause}
LithosAnanke's block storage stacks two independent caches:
\begin{enumerate}[nosep]
\item \textbf{The block-subsystem's devblock cache}
(\texttt{blk\_dev\_slot\_t.cache[DISK\_CACHE\_SLOTS]}, eight entries,
\texttt{block\_subsystem.c}). When full and a ninth distinct devblock
is needed, \texttt{cache\_get\_slot()} evicts by shifting the entire
array down one position via struct assignment:
\begin{lstlisting}[language=C]
(void) cache_writeback(slot, &slot->cache[0]);
for (int i = 0; i < DISK_CACHE_SLOTS - 1; i++)
slot->cache[i] = slot->cache[i+1];
\end{lstlisting}
The \emph{addresses} of \texttt{cache[0..7]} never move; what they
\emph{hold} does, silently.
\item \textbf{The VM-level window cache}
(\texttt{vm->blk\_vm\_cbuf[BLK\_VM\_SLOTS]}, \texttt{block\_words.c}),
used by \texttt{BLOCK}/\texttt{BUFFER}. When a block loads, it stores
the \emph{raw pointer} \texttt{blk\_get\_buffer()} returns --
\texttt{c->data + pack * BLK\_FORTH\_SIZE}, pointing directly into one
of the eight \texttt{cache\_slot\_t} structs above.
\end{enumerate}
Nothing informs layer 2 when layer 1 shifts its array. Once more than
eight distinct devblocks have been touched in one VM session, a
previously-captured window pointer can point at memory that now belongs
to a completely different devblock, with no error and no signal --
just wrong data on the next read or write through it. No prior test ever
touched enough distinct devblocks in a single session to trigger this;
the surface stress test's fifty scattered writes was the first thing
that did. This mechanism does not, on its face, predict a dependency on
LBN value rather than access pattern, which is consistent with this
report's inability to causally explain the H2 result above -- the exact
per-trial trigger condition is a complex function of window-slot reuse
and devblock-array-shift interleaving that this investigation did not
instrument further, since it is not required to confirm or fix the
defect. The defect is independent of, and predates, unrelated same-day
work on Artemis's disk-format detection (\texttt{BLK-CONFIRM-FORMAT}) --
none of that work touches \texttt{cache\_get\_slot} or the window-cache
functions.
\section{Fix}
Three call sites in \texttt{block\_words.c} wrote through the stored
window pointer before calling \texttt{blk\_update()}: \texttt{block\_word\_update}
(backing the Forth word \texttt{UPDATE}), \texttt{blk\_vm\_evict}'s
all-slots-dirty fallback, and \texttt{blk\_vm\_flush\_all} (backing
\texttt{FLUSH}/\texttt{SAVE-BUFFERS}). Each now re-resolves a
\emph{guaranteed-current} pointer by logical block number immediately
before use:
\begin{lstlisting}[language=C]
uint8_t *fresh = blk_get_buffer((uint32_t) blk, 1);
if (!fresh) { vm->error = 1; return; }
memcpy(fresh, vm->memory + base, BLOCK_SIZE);
vm->blk_vm_cbuf[s] = fresh; /* keep the window's own copy in sync */
\end{lstlisting}
\texttt{blk\_get\_buffer()} internally calls \texttt{cache\_load\_devblock()},
which correctly resolves (or reloads) whichever slot currently holds that
logical block number, however the array has shifted since the window
pointer was first captured. The fix is confined entirely to the consumer
side and does not alter the block subsystem's cache architecture: never
trust a raw cache pointer across an operation boundary where the producer
may have invalidated it -- ask for the current one again, right before
using it.
\section{Verification}
\label{sec:verification}
The fix was verified by re-running the identical stress test (same seed,
same 50-trial coprime-stride sequence) on all three supported
architectures.
\begin{table}[htb]
\centering
\begin{tabular}{lrrr}
\toprule
Run & Trials & Passed & Failed \\
\midrule
amd64 (pre-fix) & 50 & 25 & 25 \\
amd64 (post-fix) & 50 & 50 & 0 \\
aarch64 (post-fix) & 50 & 50 & 0 \\
riscv64 (post-fix) & 50 & 50 & 0 \\
\bottomrule
\end{tabular}
\caption{Surface stress test results before and after the fix.}
\end{table}
Pooling the three post-fix runs against the pre-fix run and testing
$H_0:$ ``pre-fix and post-fix trials share the same true pass rate''
with a two-proportion test rejects $H_0$ at
$p = 2.04\times10^{-19}$ (Table~\ref{tab:hypotheses}, H3; 95\% CI on the
difference in pass rate: $[-0.652, -0.348]$). This is the definitive
result in this report: unlike H1/H1b/H2/H2b, which narrow the search
space without identifying a mechanism, H3 directly confirms that the
change made in Section 5 -- and only that change -- accounts for the
difference between a 50\% and a 100\% pass rate, consistently, across
three independent instruction-set architectures.
All three post-fix architectures also completed the standard acceptance
boot to \texttt{ok>} with the fix in place, and Hera's dictionary-hash
parity across amd64 and aarch64 matched exactly for identical capsule
content, confirming the fix does not disturb cross-architecture
determinism.
\section{Disposition}
The surface stress test is now a permanent fixture of the Artemis capsule
(\texttt{capsules/artemis/init.4th}, blocks 4160--4173), invocable on
demand as \texttt{ART-STRESS} (fifty trials, fixed seed) or
\texttt{<seed> <reps> ART-STRESS-TEST} for a custom run. It is not wired
into the automatic boot sequence -- block 4170 carries the entry point
commented out (\texttt{\textbackslash\ ART-STRESS}), matching the same
disable-by-default convention already used by \texttt{ACL.4th}'s
self-activation toggle, so ordinary boots pay no extra time for it. A
future maintainer can uncomment that one line to run it automatically, or
invoke it manually from the console at any time. The unresolved H2
finding (Section 4) is left as an open question for a future
investigation with additional cache-state instrumentation, not as a
loose end in the fix itself, which H3 confirms is complete.
\end{document}
@@ -0,0 +1,5 @@
"run","label","n","passed","pass_rate","phase"
"aarch64_fixed","aarch64 (post-fix)",50,50,1,"post-fix"
"amd64_buggy","amd64 (pre-fix)",50,25,0.5,"pre-fix"
"amd64_fixed","amd64 (post-fix)",50,50,1,"post-fix"
"riscv64_fixed","riscv64 (post-fix)",50,50,1,"post-fix"
1 run label n passed pass_rate phase
2 aarch64_fixed aarch64 (post-fix) 50 50 1 post-fix
3 amd64_buggy amd64 (pre-fix) 50 25 0.5 pre-fix
4 amd64_fixed amd64 (post-fix) 50 50 1 post-fix
5 riscv64_fixed riscv64 (post-fix) 50 50 1 post-fix
@@ -0,0 +1,35 @@
#!/usr/bin/env python3
"""Convert all SVGs in charts/ to PDF for LaTeX \\includegraphics.
Mirrors experiments/bare_metal/analysis/svg_to_pdf.py, scoped to this
experiment's own charts/report/figures directories.
"""
import subprocess
import sys
from pathlib import Path
CHARTS = Path(__file__).parent / "charts"
PDFS = Path(__file__).parent / "report" / "figures"
PDFS.mkdir(parents=True, exist_ok=True)
svgs = sorted(CHARTS.glob("*.svg"))
if not svgs:
print("No SVGs found in", CHARTS)
sys.exit(1)
ok = fail = 0
for svg in svgs:
pdf = PDFS / svg.with_suffix(".pdf").name
result = subprocess.run(
["rsvg-convert", "--format=pdf", "--output", str(pdf), str(svg)],
capture_output=True, text=True
)
if result.returncode == 0:
print(f" OK {svg.name} -> {pdf.name}")
ok += 1
else:
print(f" ERR {svg.name}: {result.stderr.strip()}")
fail += 1
print(f"\n{ok} converted, {fail} failed.")
sys.exit(0 if fail == 0 else 1)
@@ -0,0 +1,20 @@
"key","value"
"h1_runs_obs",26
"h1_runs_exp",26
"h1_z",0
"h1_p",1
"h1b_W",332
"h1b_p",0.714773975516392
"h2_W",505
"h2_p",0.000107733285139378
"h2b_chisq",0.790350877192982
"h2b_df",2
"h2b_p",0.67356186013519
"h3_pre_n",50
"h3_pre_pass",25
"h3_post_n",150
"h3_post_pass",150
"h3_chisq",81.2038095238095
"h3_p",2.03599124928093e-19
"h3_ci_lo",-0.651923715768301
"h3_ci_hi",-0.348076284231699
1 key value
2 h1_runs_obs 26
3 h1_runs_exp 26
4 h1_z 0
5 h1_p 1
6 h1b_W 332
7 h1b_p 0.714773975516392
8 h2_W 505
9 h2_p 0.000107733285139378
10 h2b_chisq 0.790350877192982
11 h2b_df 2
12 h2b_p 0.67356186013519
13 h3_pre_n 50
14 h3_pre_pass 25
15 h3_post_n 150
16 h3_post_pass 150
17 h3_chisq 81.2038095238095
18 h3_p 2.03599124928093e-19
19 h3_ci_lo -0.651923715768301
20 h3_ci_hi -0.348076284231699
@@ -0,0 +1,32 @@
Artemis surface stress test -- hypothesis tests
=================================================
H1 -- pre-fix failure clustering (Wald-Wolfowitz runs test)
H0: pass/fail outcomes are independently ordered (no clustering).
Observed runs = 26 (expected under H0 = 26.00, sd = 3.50)
z = 0.000, p = 1.00e+00
-> fail to reject H0 at alpha=0.05: failures are not serially clustered.
H1b -- pre-fix outcome vs. trial/write order directly (Wilcoxon)
H0: trial index is drawn from the same distribution for PASS/FAIL
(complements H1: the runs test only catches consecutive-value
clustering, not a general rank-order trend).
W = 332.0, p = 0.715
-> fail to reject H0 at alpha=0.05: outcome is not associated with write order.
H2 -- pre-fix failure vs. disk location (Wilcoxon rank-sum test)
H0: logical block number is drawn from the same distribution
for PASS and FAIL trials (failure does not depend on location).
W = 505.0, p = 0.000
-> REJECT H0 at alpha=0.05: failure IS associated with LBN.
Secondary check -- sibling position (0/1/2) vs. outcome (chi-squared)
chi-sq = 0.790, df = 2, p = 0.674
-> fail to reject H0: outcome is not associated with sibling position.
H3 -- did the fix change the pass rate (two-proportion test)
H0: pre-fix and post-fix trials share the same true pass rate.
Pre-fix: 25/50 = 50.0% Post-fix (pooled, 3 arches): 150/150 = 100.0%
chi-sq = 81.20, df = 1, p = 2.04e-19
95% CI on the difference in pass rate: [-0.652, -0.348]
-> REJECT H0 at alpha=0.05: the fix DID CHANGE the pass rate.
@@ -0,0 +1,51 @@
trial,lbn,pat,result
0,11306,0,1
1,8587,1,1
2,3149,2,1
3,23428,3,1
4,20709,4,1
5,15271,5,1
6,12552,6,1
7,7114,7,1
8,4395,8,1
9,24674,9,1
10,21955,10,1
11,16517,11,1
12,25920,12,1
13,23201,13,1
14,20482,14,1
15,17763,15,1
16,12325,16,1
17,24447,17,1
18,21728,18,1
19,16290,19,1
20,13571,20,1
21,25693,21,1
22,22974,22,1
23,20255,23,1
24,17536,24,1
25,12098,25,1
26,3941,26,1
27,24220,27,1
28,21501,28,1
29,16063,29,1
30,13344,30,1
31,5187,31,1
32,25466,32,1
33,22747,33,1
34,20028,34,1
35,11871,35,1
36,23993,36,1
37,21274,37,1
38,13117,38,1
39,25239,39,1
40,22520,40,1
41,19801,41,1
42,17082,42,1
43,14363,43,1
44,23766,44,1
45,21047,45,1
46,18328,46,1
47,12890,47,1
48,4733,48,1
49,25012,49,1
1 trial lbn pat result
2 0 11306 0 1
3 1 8587 1 1
4 2 3149 2 1
5 3 23428 3 1
6 4 20709 4 1
7 5 15271 5 1
8 6 12552 6 1
9 7 7114 7 1
10 8 4395 8 1
11 9 24674 9 1
12 10 21955 10 1
13 11 16517 11 1
14 12 25920 12 1
15 13 23201 13 1
16 14 20482 14 1
17 15 17763 15 1
18 16 12325 16 1
19 17 24447 17 1
20 18 21728 18 1
21 19 16290 19 1
22 20 13571 20 1
23 21 25693 21 1
24 22 22974 22 1
25 23 20255 23 1
26 24 17536 24 1
27 25 12098 25 1
28 26 3941 26 1
29 27 24220 27 1
30 28 21501 28 1
31 29 16063 29 1
32 30 13344 30 1
33 31 5187 31 1
34 32 25466 32 1
35 33 22747 33 1
36 34 20028 34 1
37 35 11871 35 1
38 36 23993 36 1
39 37 21274 37 1
40 38 13117 38 1
41 39 25239 39 1
42 40 22520 40 1
43 41 19801 41 1
44 42 17082 42 1
45 43 14363 43 1
46 44 23766 44 1
47 45 21047 45 1
48 46 18328 46 1
49 47 12890 47 1
50 48 4733 48 1
51 49 25012 49 1
@@ -0,0 +1,51 @@
trial,lbn,pat,result
0,11306,0,0
1,8587,1,0
2,3149,2,0
3,20709,3,1
4,15271,4,1
5,12552,5,0
6,9833,6,1
7,7114,7,1
8,4395,8,0
9,24674,9,0
10,21955,10,1
11,16517,11,0
12,5641,12,1
13,25920,13,1
14,23201,14,1
15,20482,15,1
16,17763,16,1
17,12325,17,0
18,21728,18,0
19,16290,19,1
20,13571,20,0
21,8133,21,0
22,25693,22,1
23,17536,23,1
24,12098,24,0
25,9379,25,0
26,3941,26,0
27,21501,27,1
28,16063,28,1
29,13344,29,0
30,7906,30,0
31,5187,31,0
32,25466,32,1
33,22747,33,0
34,11871,34,0
35,3714,35,0
36,23993,36,1
37,21274,37,1
38,13117,38,0
39,22520,39,1
40,19801,40,0
41,17082,41,1
42,14363,42,1
43,8925,43,0
44,18328,44,1
45,12890,45,1
46,10171,46,0
47,4733,47,0
48,22293,48,1
49,16855,49,1
1 trial lbn pat result
2 0 11306 0 0
3 1 8587 1 0
4 2 3149 2 0
5 3 20709 3 1
6 4 15271 4 1
7 5 12552 5 0
8 6 9833 6 1
9 7 7114 7 1
10 8 4395 8 0
11 9 24674 9 0
12 10 21955 10 1
13 11 16517 11 0
14 12 5641 12 1
15 13 25920 13 1
16 14 23201 14 1
17 15 20482 15 1
18 16 17763 16 1
19 17 12325 17 0
20 18 21728 18 0
21 19 16290 19 1
22 20 13571 20 0
23 21 8133 21 0
24 22 25693 22 1
25 23 17536 23 1
26 24 12098 24 0
27 25 9379 25 0
28 26 3941 26 0
29 27 21501 27 1
30 28 16063 28 1
31 29 13344 29 0
32 30 7906 30 0
33 31 5187 31 0
34 32 25466 32 1
35 33 22747 33 0
36 34 11871 34 0
37 35 3714 35 0
38 36 23993 36 1
39 37 21274 37 1
40 38 13117 38 0
41 39 22520 39 1
42 40 19801 40 0
43 41 17082 41 1
44 42 14363 42 1
45 43 8925 43 0
46 44 18328 44 1
47 45 12890 45 1
48 46 10171 46 0
49 47 4733 47 0
50 48 22293 48 1
51 49 16855 49 1
@@ -0,0 +1,51 @@
trial,lbn,pat,result
0,11306,0,1
1,8587,1,1
2,3149,2,1
3,23428,3,1
4,20709,4,1
5,15271,5,1
6,12552,6,1
7,7114,7,1
8,4395,8,1
9,24674,9,1
10,21955,10,1
11,16517,11,1
12,25920,12,1
13,23201,13,1
14,20482,14,1
15,17763,15,1
16,12325,16,1
17,24447,17,1
18,21728,18,1
19,16290,19,1
20,13571,20,1
21,25693,21,1
22,22974,22,1
23,20255,23,1
24,17536,24,1
25,12098,25,1
26,3941,26,1
27,24220,27,1
28,21501,28,1
29,16063,29,1
30,13344,30,1
31,5187,31,1
32,25466,32,1
33,22747,33,1
34,20028,34,1
35,11871,35,1
36,23993,36,1
37,21274,37,1
38,13117,38,1
39,25239,39,1
40,22520,40,1
41,19801,41,1
42,17082,42,1
43,14363,43,1
44,23766,44,1
45,21047,45,1
46,18328,46,1
47,12890,47,1
48,4733,48,1
49,25012,49,1
1 trial lbn pat result
2 0 11306 0 1
3 1 8587 1 1
4 2 3149 2 1
5 3 23428 3 1
6 4 20709 4 1
7 5 15271 5 1
8 6 12552 6 1
9 7 7114 7 1
10 8 4395 8 1
11 9 24674 9 1
12 10 21955 10 1
13 11 16517 11 1
14 12 25920 12 1
15 13 23201 13 1
16 14 20482 14 1
17 15 17763 15 1
18 16 12325 16 1
19 17 24447 17 1
20 18 21728 18 1
21 19 16290 19 1
22 20 13571 20 1
23 21 25693 21 1
24 22 22974 22 1
25 23 20255 23 1
26 24 17536 24 1
27 25 12098 25 1
28 26 3941 26 1
29 27 24220 27 1
30 28 21501 28 1
31 29 16063 29 1
32 30 13344 30 1
33 31 5187 31 1
34 32 25466 32 1
35 33 22747 33 1
36 34 20028 34 1
37 35 11871 35 1
38 36 23993 36 1
39 37 21274 37 1
40 38 13117 38 1
41 39 25239 39 1
42 40 22520 40 1
43 41 19801 41 1
44 42 17082 42 1
45 43 14363 43 1
46 44 23766 44 1
47 45 21047 45 1
48 46 18328 46 1
49 47 12890 47 1
50 48 4733 48 1
51 49 25012 49 1
@@ -0,0 +1,51 @@
trial,lbn,pat,result
0,11306,0,1
1,8587,1,1
2,3149,2,1
3,23428,3,1
4,20709,4,1
5,15271,5,1
6,12552,6,1
7,7114,7,1
8,4395,8,1
9,24674,9,1
10,21955,10,1
11,16517,11,1
12,25920,12,1
13,23201,13,1
14,20482,14,1
15,17763,15,1
16,12325,16,1
17,24447,17,1
18,21728,18,1
19,16290,19,1
20,13571,20,1
21,25693,21,1
22,22974,22,1
23,20255,23,1
24,17536,24,1
25,12098,25,1
26,3941,26,1
27,24220,27,1
28,21501,28,1
29,16063,29,1
30,13344,30,1
31,5187,31,1
32,25466,32,1
33,22747,33,1
34,20028,34,1
35,11871,35,1
36,23993,36,1
37,21274,37,1
38,13117,38,1
39,25239,39,1
40,22520,40,1
41,19801,41,1
42,17082,42,1
43,14363,43,1
44,23766,44,1
45,21047,45,1
46,18328,46,1
47,12890,47,1
48,4733,48,1
49,25012,49,1
1 trial lbn pat result
2 0 11306 0 1
3 1 8587 1 1
4 2 3149 2 1
5 3 23428 3 1
6 4 20709 4 1
7 5 15271 5 1
8 6 12552 6 1
9 7 7114 7 1
10 8 4395 8 1
11 9 24674 9 1
12 10 21955 10 1
13 11 16517 11 1
14 12 25920 12 1
15 13 23201 13 1
16 14 20482 14 1
17 15 17763 15 1
18 16 12325 16 1
19 17 24447 17 1
20 18 21728 18 1
21 19 16290 19 1
22 20 13571 20 1
23 21 25693 21 1
24 22 22974 22 1
25 23 20255 23 1
26 24 17536 24 1
27 25 12098 25 1
28 26 3941 26 1
29 27 24220 27 1
30 28 21501 28 1
31 29 16063 29 1
32 30 13344 30 1
33 31 5187 31 1
34 32 25466 32 1
35 33 22747 33 1
36 34 20028 34 1
37 35 11871 35 1
38 36 23993 36 1
39 37 21274 37 1
40 38 13117 38 1
41 39 25239 39 1
42 40 22520 40 1
43 41 19801 41 1
44 42 17082 42 1
45 43 14363 43 1
46 44 23766 44 1
47 45 21047 45 1
48 46 18328 46 1
49 47 12890 47 1
50 48 4733 48 1
51 49 25012 49 1
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff