use std::collections::HashSet;
use crate::conscience::{self, Challenge, Names};
pub const TOKENS: usize = 12_000;
pub const QUESTION_CHARS: usize = 240;
pub const CONSEQUENCE_CHARS: usize = 160;
pub use borg_trace::CHARS_PER_TOKEN;
pub fn on() -> bool {
!std::env::var("BORG_STOP_POOL").is_ok_and(|v| v.trim().eq_ignore_ascii_case("shortlist"))
}
pub fn classic() -> bool {
std::env::var("BORG_STOP_FORMAT").is_ok_and(|v| v.trim().eq_ignore_ascii_case("classic"))
}
pub fn graded() -> bool {
!std::env::var("BORG_STOP_GRADED").is_ok_and(|v| v.trim().eq_ignore_ascii_case("off"))
}
pub fn tokens() -> usize {
std::env::var("BORG_STOP_POOL_TOKENS").ok().and_then(|v| v.trim().parse().ok()).unwrap_or(TOKENS)
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Line {
A1,
A2,
}
impl Line {
#[must_use]
pub fn name(self) -> &'static str {
match self {
Line::A1 => "a1",
Line::A2 => "a2",
}
}
}
#[must_use]
pub fn line_format() -> Line {
if std::env::var("BORG_LESSON_LINE").is_ok_and(|v| v.trim().eq_ignore_ascii_case("a1")) { Line::A1 } else { Line::A2 }
}
pub fn line(c: &Challenge) -> String {
let correction = (line_format() == Line::A2).then_some(c.correction.as_str());
line_with(c, correction)
}
pub fn line_with(c: &Challenge, correction: Option<&str>) -> String {
let words = |s: &str| s.split_whitespace().collect::<Vec<_>>().join(" ");
let flat = |s: &str, n: usize| crate::predict::clip(&words(s), n);
let q = flat(&c.question, QUESTION_CHARS);
let a1 = if c.consequence.trim().is_empty() { format!("[{}] {q}", c.id) } else { format!("[{}] {q} -> {}", c.id, flat(&c.consequence, CONSEQUENCE_CHARS)) };
match correction.map(words).filter(|w| !w.is_empty()) {
Some(said) => format!("{a1} | the engineer's correction: \"{said}\""),
None => a1,
}
}
pub fn cost(c: &Challenge) -> usize {
(line(c).chars().count() + 1).div_ceil(CHARS_PER_TOKEN)
}
pub fn eligible<'a>(pool: &'a [Challenge], ranked: &[(f64, &'a Challenge)], scope_text: &str) -> Vec<&'a Challenge> {
let have = Names::of(scope_text);
let successors = crate::trust::successors(pool);
let recalled: HashSet<&str> = ranked.iter().map(|(_, c)| c.id.as_str()).collect();
pool.iter()
.filter(|c| !c.off_system && conscience::in_scope(c, &have) && !successors.contains_key(&c.id))
.filter(|c| !c.dormant || recalled.contains(c.id.as_str()))
.collect()
}
pub fn select<'a>(
eligible: Vec<&'a Challenge>,
shortlist: impl FnOnce() -> Vec<&'a Challenge>,
ranked: &[(f64, &'a Challenge)],
tokens: usize,
) -> (Vec<&'a Challenge>, bool) {
let f = select_filled(eligible, shortlist, ranked, tokens);
(f.shown, f.fell)
}
#[derive(Debug, Clone)]
pub struct Filled<'a> {
pub shown: Vec<&'a Challenge>,
pub fell: bool,
pub order: Vec<&'a Challenge>,
pub dropped: Vec<&'a Challenge>,
}
pub fn select_filled<'a>(
eligible: Vec<&'a Challenge>,
shortlist: impl FnOnce() -> Vec<&'a Challenge>,
ranked: &[(f64, &'a Challenge)],
tokens: usize,
) -> Filled<'a> {
let allowed: HashSet<&str> = eligible.iter().map(|c| c.id.as_str()).collect();
let mut rest: Vec<&Challenge> = eligible.clone();
rest.sort_by_key(|l| std::cmp::Reverse(l.origin_ms));
let fits = eligible.iter().map(|c| cost(c)).sum::<usize>() <= tokens;
let first = if fits { Vec::new() } else { shortlist() };
let order = first.into_iter().chain(ranked.iter().map(|(_, c)| *c)).chain(rest);
let (mut picked, mut dropped): (Vec<&Challenge>, Vec<&Challenge>) = (Vec::new(), Vec::new());
let mut met: HashSet<&str> = HashSet::new();
let mut used = 0;
for c in order {
if !allowed.contains(c.id.as_str()) || !met.insert(c.id.as_str()) {
continue;
}
let k = cost(c);
if fits || used + k <= tokens {
used += k;
picked.push(c);
} else {
dropped.push(c);
}
}
if fits {
return Filled { shown: eligible, fell: false, order: picked, dropped };
}
let shown: HashSet<&str> = picked.iter().map(|c| c.id.as_str()).collect();
Filled { shown: eligible.into_iter().filter(|c| shown.contains(c.id.as_str())).collect(), fell: true, order: picked, dropped }
}
pub const TAIL_SAMPLE: usize = 2;
pub const BOUNDARY_SHARE: f64 = 0.15;
#[must_use]
pub fn boundary_share() -> f64 {
if std::env::var("BORG_BOUNDARY").is_ok_and(|v| v.trim().eq_ignore_ascii_case("off")) { 0.0 } else { BOUNDARY_SHARE }
}
#[must_use]
pub fn tail_k(costs: &[usize], s: f64, tokens: usize) -> usize {
let n = costs.len();
if n == 0 {
return 0;
}
let mean = costs.iter().sum::<usize>().div_ceil(n).max(1);
let room = (s * tokens as f64).floor() as usize;
n.min(TAIL_SAMPLE.max(room / mean))
}
#[must_use]
pub fn tail<'a>(dropped: &[&'a Challenge], seed: u64, s: f64, tokens: usize) -> (Vec<(usize, &'a Challenge)>, f64) {
let costs: Vec<usize> = dropped.iter().map(|c| cost(c)).collect();
let (n, k) = (dropped.len(), tail_k(&costs, s, tokens));
if k == 0 {
return (Vec::new(), 0.0);
}
let mut at: Vec<usize> = (0..n).collect();
let mut rng = crate::memory::Rng::new(seed);
for i in 0..k {
let j = i + (rng.next_u64() % (n - i) as u64) as usize;
at.swap(i, j);
}
let mut drawn = at[..k].to_vec();
drawn.sort_unstable();
(drawn.into_iter().map(|i| (i, dropped[i])).collect(), k as f64 / n as f64)
}
#[derive(Debug, Clone)]
pub struct Explored<'a> {
pub filled: Filled<'a>,
pub tail: Vec<(usize, &'a Challenge)>,
pub pt: f64,
pub boundary: Vec<(usize, &'a Challenge)>,
pub tau: usize,
pub s: f64,
pub k: usize,
pub n: usize,
pub window: usize,
pub seed: u64,
}
impl Explored<'_> {
#[must_use]
pub fn drawn(&self) -> usize {
self.boundary.len() + self.tail.len()
}
#[must_use]
pub fn chances(&self) -> (Vec<Option<f64>>, Vec<f64>) {
let costs: Vec<usize> = self.filled.dropped.iter().map(|c| cost(c)).collect();
inclusion(&costs, self.window, self.tau, self.k, self.seed, self.pt)
}
}
pub fn explore<'a>(
eligible: Vec<&'a Challenge>,
shortlist: impl FnOnce() -> Vec<&'a Challenge>,
ranked: &[(f64, &'a Challenge)],
tokens: usize,
s: f64,
seed: u64,
) -> Explored<'a> {
let fits = eligible.iter().map(|c| cost(c)).sum::<usize>() <= tokens;
let prefix = if fits { tokens } else { ((1.0 - s) * tokens as f64).floor() as usize };
let filled = select_filled(eligible, shortlist, ranked, prefix);
let at = filled.order.len();
let used: usize = filled.order.iter().map(|c| cost(c)).sum();
let window = tokens.saturating_sub(used);
let costs: Vec<usize> = filled.dropped.iter().map(|c| cost(c)).collect();
let tau = greedy(&costs, window);
let b_seed = seed ^ u64::from_be_bytes(*b"boundary");
let (drawn, pt) = if at == 0 { (Vec::new(), 0.0) } else { tail(&filled.dropped, seed, s, tokens) };
let mut boundary = draw_boundary(&costs, &drawn.iter().map(|(i, _)| *i).collect::<Vec<_>>(), window, tau, b_seed);
let pt = if drawn.is_empty() { 0.0 } else { pt };
let k = drawn.len();
let tail = drawn.into_iter().map(|(i, c)| (at + i, c)).collect();
boundary.sort_unstable();
let boundary = boundary.into_iter().map(|i| (at + i, filled.dropped[i])).collect();
let n = filled.dropped.len();
Explored { filled, tail, pt, boundary, tau, s, k, n, window, seed: b_seed }
}
fn greedy(costs: &[usize], window: usize) -> usize {
let mut left = window;
costs
.iter()
.filter(|&&k| {
let fit = k <= left;
if fit {
left -= k;
}
fit
})
.count()
}
fn draw_boundary(costs: &[usize], taken: &[usize], window: usize, tau: usize, seed: u64) -> Vec<usize> {
let mut out = Vec::new();
if tau == 0 {
return out;
}
let mut rng = crate::memory::Rng::new(seed);
let mut out_of = vec![false; costs.len()];
for &i in taken {
out_of[i] = true;
}
let mut open: Vec<usize> = (0..costs.len()).filter(|&i| !out_of[i]).collect();
let mut left = window;
loop {
let fit: Vec<usize> = open.iter().copied().filter(|&i| costs[i] <= left).collect();
let Some(&first) = fit.first() else { break };
let w: Vec<f64> = fit.iter().map(|&i| (-((i - first) as f64) / tau as f64).exp()).collect();
let mut u = rng.unit() * w.iter().sum::<f64>();
let mut pick = *fit.last().unwrap_or(&first);
for (&i, &wi) in fit.iter().zip(&w) {
if u < wi {
pick = i;
break;
}
u -= wi;
}
left -= costs[pick];
out.push(pick);
open.retain(|&i| i != pick);
}
out
}
fn inclusion(costs: &[usize], window: usize, tau: usize, k: usize, seed: u64, pt: f64) -> (Vec<Option<f64>>, Vec<f64>) {
let n = costs.len();
let (mut hit, mut open) = (vec![0usize; n], vec![0usize; n]);
if tau > 0 {
let mut seeds = crate::memory::Rng::new(seed ^ u64::from_be_bytes(*b"replayed"));
let k = if pt > 0.0 { k } else { 0 };
for _ in 0..crate::conscience::P_DRAWS {
let mut rng = crate::memory::Rng::new(seeds.next_u64());
let mut at: Vec<usize> = (0..n).collect();
for i in 0..k {
let j = i + (rng.next_u64() % (n - i) as u64) as usize;
at.swap(i, j);
}
let taken = &at[..k];
for i in at[k..].iter() {
open[*i] += 1;
}
for i in draw_boundary(costs, taken, window, tau, seeds.next_u64()) {
hit[i] += 1;
}
}
}
let pb: Vec<Option<f64>> = (0..n).map(|i| if tau == 0 { Some(0.0) } else { (open[i] > 0).then(|| hit[i] as f64 / open[i] as f64) }).collect();
let pi = pb.iter().map(|b| pt + (1.0 - pt) * b.unwrap_or(0.0)).collect();
(pb, pi)
}
#[cfg(test)]
mod tests {
use super::*;
fn lesson(id: &str, q: &str, ms: i64) -> Challenge {
Challenge { id: id.into(), question: q.into(), consequence: "bad".into(), origin_ms: ms, ..Default::default() }
}
fn ids(v: &[&Challenge]) -> Vec<String> {
v.iter().map(|c| c.id.clone()).collect()
}
#[test]
fn a_line_is_trimmed_and_flat() {
let c = Challenge { id: "L1".into(), question: format!("Did I\n check {}?", "x".repeat(500)), consequence: "c\nd".into(), ..Default::default() };
let l = line(&c);
assert!(l.starts_with("[L1] Did I check x") && l.ends_with("… -> c d") && !l.contains('\n'), "{l}");
assert!(l.chars().count() < QUESTION_CHARS + 20, "{}", l.len());
assert_eq!(line(&Challenge { id: "q".into(), question: "Q?".into(), ..Default::default() }), "[q] Q?");
}
#[test]
fn an_a2_line_carries_the_correction_and_falls_back() {
let said = format!("no,\n drain the budget {}", "y".repeat(1400));
let c = Challenge {
id: "L1".into(),
question: "Is the budget drained?".into(),
consequence: "a stuck net".into(),
correction: said.clone(),
..Default::default()
};
let a1 = line_with(&c, None);
assert_eq!(a1, "[L1] Is the budget drained? -> a stuck net");
let a2 = line_with(&c, Some(&said));
assert_eq!(a2, format!("{a1} | the engineer's correction: \"no, drain the budget {}\"", "y".repeat(1400)), "flat, never clipped");
assert_eq!(line_with(&c, Some(" \n ")), a1, "an empty correction is no correction");
let peer = Challenge { correction: String::new(), ..c.clone() };
assert_eq!(line(&peer), a1);
assert!(cost(&c) > cost(&peer), "the budget counts the correction");
assert_eq!((Line::A1.name(), Line::A2.name()), ("a1", "a2"));
}
#[test]
fn the_pool_honours_scope_system_supersession_and_dormancy() {
let mut pool = vec![
lesson("free", "generic question about tests", 1),
Challenge { scope: vec!["Orion".into()], ..lesson("orion", "orion drain rule", 2) },
Challenge { scope: vec!["Beacon".into()], ..lesson("beacon", "beacon relaxed baseline", 3) },
Challenge { off_system: true, ..lesson("other", "another system", 4) },
lesson("old", "the old rule about locks", 5),
Challenge { supersedes: vec!["old".into()], source: "queen".into(), ..lesson("new", "the new rule about locks", 6) },
Challenge { dormant: true, ..lesson("sleepy", "dormant lesson about caches", 7) },
Challenge { dormant: true, ..lesson("woken", "dormant lesson about websocket deadlocks", 8) },
];
pool[5].trust = 0.9;
let scope = "repo orion-text\nwork on the websocket deadlocks";
let ranked = conscience::rank_scoped(&pool, "websocket deadlocks", scope);
assert_eq!(ids(&eligible(&pool, &ranked, scope)), ["free", "orion", "new", "woken"]);
}
#[test]
fn everything_fits_in_store_order_else_the_shortlist_order_fills_the_budget() {
let pool: Vec<Challenge> = (0..10).map(|i| lesson(&format!("L{i}"), &format!("question number {i} about topic{i}"), i)).collect();
let all: Vec<&Challenge> = pool.iter().collect();
let each = cost(&pool[0]);
let mut called = false;
let ranked = vec![(3.0, &pool[7]), (2.0, &pool[5]), (1.0, &pool[2])];
let f = select_filled(
all.clone(),
|| {
called = true;
vec![]
},
&ranked,
10 * each,
);
assert_eq!((f.shown.len(), f.fell, called, f.dropped.len()), (10, false, false, 0), "fits: no shortlist needed");
assert_eq!(ids(&f.order), ["L7", "L5", "L2", "L9", "L8", "L6", "L4", "L3", "L1", "L0"]);
let f = select_filled(all, || vec![&pool[7], &pool[2]], &ranked, 4 * each);
assert!(f.fell);
assert_eq!(ids(&f.shown), ["L2", "L5", "L7", "L9"]);
assert_eq!(ids(&f.order), ["L7", "L2", "L5", "L9"], "the order they took the budget in");
assert!(f.shown.iter().map(|c| cost(c)).sum::<usize>() <= 4 * each);
assert_eq!(ids(&f.dropped), ["L8", "L6", "L4", "L3", "L1", "L0"]);
}
#[test]
fn the_budget_never_shows_a_lesson_outside_the_eligible_set() {
let pool: Vec<Challenge> = (0..4).map(|i| lesson(&format!("L{i}"), "q", i)).collect();
let elig = vec![&pool[0], &pool[1]];
let f = select_filled(elig, || vec![&pool[3], &pool[2], &pool[1]], &[(1.0, &pool[3])], 1);
assert!(f.shown.is_empty() && f.order.is_empty(), "budget too small for any line");
assert_eq!(ids(&f.dropped), ["L1", "L0"], "dropped, but never one outside the eligible set");
let f = select_filled(vec![&pool[0], &pool[1]], || vec![&pool[3], &pool[1]], &[], cost(&pool[1]));
assert_eq!((ids(&f.shown), f.fell, ids(&f.order), ids(&f.dropped)), (vec!["L1".to_string()], true, vec!["L1".to_string()], vec!["L0".to_string()]));
}
#[test]
fn the_tail_is_a_small_uniform_seeded_sample_of_what_the_budget_dropped() {
let pool: Vec<Challenge> = (0..10).map(|i| lesson(&format!("D{i}"), "q", i)).collect();
let dropped: Vec<&Challenge> = pool.iter().collect();
let (t, pt) = tail(&dropped, 7, BOUNDARY_SHARE, 0);
assert_eq!((t.len(), pt), (TAIL_SAMPLE, TAIL_SAMPLE as f64 / 10.0));
assert!(t.windows(2).all(|w| w[0].0 < w[1].0), "in the order the fill met them: {t:?}");
assert!(t.iter().all(|(i, c)| dropped[*i].id == c.id));
let at = |t: &[(usize, &Challenge)]| t.iter().map(|(i, _)| *i).collect::<Vec<_>>();
assert_eq!(at(&tail(&dropped, 7, BOUNDARY_SHARE, 0).0), at(&t), "seeded");
let mut hits = [0usize; 10];
for seed in 0..10_000 {
for (i, _) in tail(&dropped, seed, BOUNDARY_SHARE, 0).0 {
hits[i] += 1;
}
}
assert!(hits.iter().all(|h| (1_700..2_300).contains(h)), "{hits:?}");
let (all, pt) = tail(&dropped[..1], 3, BOUNDARY_SHARE, 0);
assert_eq!((all.len(), pt), (1, 1.0), "fewer than the sample: all of them, surely");
let (none, pt) = tail(&[], 3, BOUNDARY_SHARE, 0);
assert!(none.is_empty() && pt == 0.0);
}
#[test]
fn the_tail_is_uniform_over_the_remainder_and_pt_is_k_over_n() {
let ten = [10usize; 40];
assert_eq!((tail_k(&ten, 0.15, 400), tail_k(&[10; 400], 0.15, 400), tail_k(&ten[..10], 0.15, 100)), (6, 6, 2));
assert_eq!((tail_k(&ten[..1], 0.15, 400), tail_k(&ten, 0.0, 400), tail_k(&[], 0.15, 400), tail_k(&[0, 0], 0.15, 400)), (1, 2, 0, 2));
let pool: Vec<Challenge> = (0..40).map(|i| lesson(&format!("D{i}"), "q", i)).collect();
let dropped: Vec<&Challenge> = pool.iter().collect();
let tokens = 40 * cost(&pool[0]) + 1;
let (t, pt) = tail(&dropped, 11, 0.15, tokens);
assert_eq!((t.len(), pt), (6, 6.0 / 40.0));
let mut hits = [0usize; 40];
for seed in 0..20_000 {
for (i, _) in tail(&dropped, seed, 0.15, tokens).0 {
hits[i] += 1;
}
}
assert!(hits.iter().all(|h| (2_700..3_300).contains(h)), "{hits:?}");
}
fn overflowing() -> Vec<Challenge> {
(0..10).map(|i| lesson(&format!("B{i}"), &format!("question {i} {}", "w ".repeat(10 + 7 * (i % 3) as usize)), i)).collect()
}
#[test]
fn boundary_off_is_todays_fill() {
let pool = overflowing();
let all: Vec<&Challenge> = pool.iter().collect();
let budget = cost(&pool[0]) * 4;
for seed in 0..50 {
let e = explore(all.clone(), Vec::new, &[], budget, 0.0, seed);
let today = select_filled(all.clone(), Vec::new, &[], budget);
assert_eq!((ids(&e.filled.order), ids(&e.filled.dropped)), (ids(&today.order), ids(&today.dropped)));
assert!(e.boundary.is_empty() && e.tau == 0 && e.chances().0.iter().all(|b| *b == Some(0.0)), "{e:?}");
assert_eq!((e.tail.len(), e.pt), (TAIL_SAMPLE, TAIL_SAMPLE as f64 / today.dropped.len() as f64));
let (t, _) = tail(&today.dropped, seed, 0.0, 0);
assert_eq!(
e.tail.iter().map(|(i, c)| (*i, c.id.clone())).collect::<Vec<_>>(),
t.iter().map(|(i, c)| (today.order.len() + i, c.id.clone())).collect::<Vec<_>>()
);
}
let e = explore(all.clone(), Vec::new, &[], usize::MAX / 2, BOUNDARY_SHARE, 1);
assert_eq!((e.filled.order.len(), e.drawn(), e.n), (10, 0, 0));
}
#[test]
fn an_empty_prefix_draws_the_boundary_without_a_tail() {
let pool = [lesson("A", "same words here", 1), lesson("B", "same words also", 2)];
let all: Vec<&Challenge> = pool.iter().collect();
let budget = cost(&pool[0]);
assert_eq!(cost(&pool[1]), budget);
for seed in 0..20 {
let e = explore(all.clone(), Vec::new, &[], budget, BOUNDARY_SHARE, seed);
assert_eq!((e.filled.order.len(), e.tail.len(), e.pt, e.boundary.len()), (0, 0, 0.0, 1), "{e:?}");
let (pb, pi) = e.chances();
let first = 1.0 / (1.0 + (-1.0f64).exp());
assert_eq!(pb.iter().map(|b| b.unwrap_or(-1.0)).collect::<Vec<_>>(), pi, "no tail: π is π_b");
assert!((pi[0] - first).abs() < 0.05 && (pi[0] + pi[1] - 1.0).abs() < 1e-9, "{pi:?}");
}
}
#[test]
fn boundary_pi_matches_frequency() {
let pool = overflowing();
let all: Vec<&Challenge> = pool.iter().collect();
let budget = cost(&pool[0]) * 4;
let first = explore(all.clone(), Vec::new, &[], budget, BOUNDARY_SHARE, 0);
let n = first.n;
assert!(n > 0 && first.tau > 0, "the scenario draws: {first:?}");
let (mut shown, mut boundary, mut open) = (vec![0usize; n], vec![0usize; n], vec![0usize; n]);
let (mut pb, mut pi) = (vec![0.0; n], vec![0.0; n]);
let at = first.filled.order.len();
const SEEDS: u64 = 10_000;
const ESTIMATES: u64 = 100;
for seed in 0..SEEDS {
let e = explore(all.clone(), Vec::new, &[], budget, BOUNDARY_SHARE, seed);
assert_eq!(ids(&e.filled.order), ids(&first.filled.order), "the prefix is deterministic");
let used: usize = e.filled.order.iter().chain(e.boundary.iter().map(|(_, c)| c)).map(|c| cost(c)).sum();
assert!(used <= budget, "within the budget");
assert!(e.boundary.iter().all(|(b, _)| e.tail.iter().all(|(t, _)| t != b)), "never a tail lesson");
let tail: Vec<usize> = e.tail.iter().map(|(i, _)| i - at).collect();
for (i, o) in open.iter_mut().enumerate() {
*o += usize::from(!tail.contains(&i));
}
for (i, _) in &e.boundary {
boundary[i - at] += 1;
}
for i in tail.iter().copied().chain(e.boundary.iter().map(|(i, _)| i - at)) {
shown[i] += 1;
}
if seed < ESTIMATES {
let (epb, epi) = e.chances();
for (i, (b, p)) in pb.iter_mut().zip(pi.iter_mut()).enumerate() {
*b += epb[i].unwrap_or(0.0) / ESTIMATES as f64;
*p += epi[i] / ESTIMATES as f64;
}
}
}
for i in 0..n {
let (b, p) = (boundary[i] as f64 / open[i] as f64, shown[i] as f64 / SEEDS as f64);
assert!((pb[i] - b).abs() <= 0.03, "π_b at {i}: {} vs {b}", pb[i]);
assert!((pi[i] - p).abs() <= 0.03, "π at {i}: {} vs {p}", pi[i]);
}
assert!(boundary.windows(2).any(|w| w[0] > w[1]), "the draw favours the fill order's first: {boundary:?}");
}
}