Compare commits
No commits in common. "6487d33f27915a69f25fecc9b129d2d7bbf972f5" and "b8894e84b535b7d35cb513ac49dd34192f3b0976" have entirely different histories.
6487d33f27
...
b8894e84b5
13 changed files with 12 additions and 1196 deletions
1
Makefile
1
Makefile
|
|
@ -119,7 +119,6 @@ self-tests:
|
||||||
$(PY) $(TOOLS)/size-metrics.py --self-test
|
$(PY) $(TOOLS)/size-metrics.py --self-test
|
||||||
$(PY) $(TOOLS)/runtime-metrics.py --self-test
|
$(PY) $(TOOLS)/runtime-metrics.py --self-test
|
||||||
$(PY) $(TOOLS)/replay-test.py --self-test
|
$(PY) $(TOOLS)/replay-test.py --self-test
|
||||||
$(PY) $(TOOLS)/design-baseline.py --self-test
|
|
||||||
|
|
||||||
# T01 positive control: prove the environment fix, do not assume it. Runs
|
# T01 positive control: prove the environment fix, do not assume it. Runs
|
||||||
# every tool from a foreign working directory with a PATH that has no
|
# every tool from a foreign working directory with a PATH that has no
|
||||||
|
|
|
||||||
|
|
@ -147,11 +147,6 @@ is what the 27% breach called for.
|
||||||
- **The engine still has not imported the edition data**, now that
|
- **The engine still has not imported the edition data**, now that
|
||||||
GROUND-WP-0002 T01 has ruled it authoritative. That is the next product
|
GROUND-WP-0002 T01 has ruled it authoritative. That is the next product
|
||||||
pass, and it is what makes the ending's `0` scores and `winners nobody`
|
pass, and it is what makes the ending's `0` scores and `winners nobody`
|
||||||
meaningful — ~~confirmed as the stand-in's doing, not a scoring bug~~.
|
meaningful — **confirmed as the stand-in's doing, not a scoring bug**.
|
||||||
**CORRECTED 2026-08-03 (CB-WP-0021):** overstated. The `0` came from no
|
|
||||||
Problem being claimed at all. The *threshold* gap is independent of the
|
|
||||||
dataset — GR-S01 deals 2/3/4 of the five problems, so 4/6/9 points are
|
|
||||||
in play against thresholds of 5/7/9, unreachable at 2p and 3–4p with
|
|
||||||
either dataset.
|
|
||||||
- **`ground-game` owes ten rulings** (U1–U10) and SOLVE's legality.
|
- **`ground-game` owes ten rulings** (U1–U10) and SOLVE's legality.
|
||||||
- **Chaos: 3 of 12 in window 2, one override, changed nothing.**
|
- **Chaos: 3 of 12 in window 2, one override, changed nothing.**
|
||||||
|
|
|
||||||
18
facts.toml
18
facts.toml
|
|
@ -6,7 +6,7 @@
|
||||||
# `make facts-check` fails if this file disagrees with the
|
# `make facts-check` fails if this file disagrees with the
|
||||||
# instruments, or if a tagged artifact disagrees with this file.
|
# instruments, or if a tagged artifact disagrees with this file.
|
||||||
|
|
||||||
generated = "2026-08-04"
|
generated = "2026-08-03"
|
||||||
pin = "fc76445"
|
pin = "fc76445"
|
||||||
|
|
||||||
[am4a_loc]
|
[am4a_loc]
|
||||||
|
|
@ -46,26 +46,26 @@ fmt = "{:,}"
|
||||||
by = "tools/mutation-check.py"
|
by = "tools/mutation-check.py"
|
||||||
|
|
||||||
[gr_covered]
|
[gr_covered]
|
||||||
value = 59
|
value = 58
|
||||||
text = "59"
|
text = "58"
|
||||||
fmt = "{:,}"
|
fmt = "{:,}"
|
||||||
by = "tools/rule-coverage.py"
|
by = "tools/rule-coverage.py"
|
||||||
|
|
||||||
[gr_linked]
|
[gr_linked]
|
||||||
value = 50
|
value = 49
|
||||||
text = "50"
|
text = "49"
|
||||||
fmt = "{:,}"
|
fmt = "{:,}"
|
||||||
by = "tools/rule-coverage.py"
|
by = "tools/rule-coverage.py"
|
||||||
|
|
||||||
[gr_rules]
|
[gr_rules]
|
||||||
value = 59
|
value = 58
|
||||||
text = "59"
|
text = "58"
|
||||||
fmt = "{:,}"
|
fmt = "{:,}"
|
||||||
by = "tools/rule-coverage.py"
|
by = "tools/rule-coverage.py"
|
||||||
|
|
||||||
[gr_scenarios]
|
[gr_scenarios]
|
||||||
value = 26
|
value = 25
|
||||||
text = "26"
|
text = "25"
|
||||||
fmt = "{:,}"
|
fmt = "{:,}"
|
||||||
by = "tools/rule-coverage.py"
|
by = "tools/rule-coverage.py"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -153,17 +153,6 @@ pub fn legal_commands(state: &GroundState, seat: PlayerId) -> Vec<GroundCommand>
|
||||||
Action::Ground,
|
Action::Ground,
|
||||||
] {
|
] {
|
||||||
match action {
|
match action {
|
||||||
// Offered on every Problem; `validate` decides
|
|
||||||
// which are legal, and this function filters every
|
|
||||||
// candidate through it below.
|
|
||||||
//
|
|
||||||
// CB-WP-0023 first put GR-P05's conditions here, in
|
|
||||||
// the OFFER layer. The AM-1 coverage gate then asked
|
|
||||||
// for a scenario covering GR-P05 — and scenarios drive
|
|
||||||
// `validate`, not this. That is what revealed the rule
|
|
||||||
// belonged in `validate`: a rule enforced only by the
|
|
||||||
// offer is enforced only for clients that ask what is
|
|
||||||
// legal. Once it moved, everything here was dead code.
|
|
||||||
Action::Investigate | Action::Solve => {
|
Action::Investigate | Action::Solve => {
|
||||||
for problem in &problems {
|
for problem in &problems {
|
||||||
candidates.push(GroundCommand::SelectAction {
|
candidates.push(GroundCommand::SelectAction {
|
||||||
|
|
@ -660,178 +649,6 @@ mod tests {
|
||||||
.expect("preset")
|
.expect("preset")
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------
|
|
||||||
// CB-WP-0023: SOLVE's legality, ruled by ground-game 2026-08-03.
|
|
||||||
//
|
|
||||||
// Four conditions, each asserted on its own, because a single
|
|
||||||
// "SOLVE is filtered" test would pass with three of the four
|
|
||||||
// implemented and nobody would know which.
|
|
||||||
|
|
||||||
/// Problems that SOLVE is offered on, for `seat`.
|
|
||||||
fn solvable(state: &GroundState, seat: PlayerId) -> Vec<u32> {
|
|
||||||
legal_commands(state, seat)
|
|
||||||
.into_iter()
|
|
||||||
.filter_map(|c| match c {
|
|
||||||
GroundCommand::SelectAction {
|
|
||||||
action: Action::Solve,
|
|
||||||
problem: Some(n),
|
|
||||||
..
|
|
||||||
} => Some(n),
|
|
||||||
_ => None,
|
|
||||||
})
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A 3p game where seat 0 can solve exactly problem 1.
|
|
||||||
fn solvable_fixture() -> (GroundState, u32) {
|
|
||||||
let mut st = setup(3, 42);
|
|
||||||
let (n, suit) = st
|
|
||||||
.problems
|
|
||||||
.iter()
|
|
||||||
.find(|(_, p)| p.face_up)
|
|
||||||
.map(|(n, p)| (*n, p.suit))
|
|
||||||
.expect("GR-S01 deals one face-up Surface Problem");
|
|
||||||
// Give seat 0 the matching Solution, so the ONLY thing under test
|
|
||||||
// is the condition each case perturbs.
|
|
||||||
st.players.get_mut(&PlayerId(0)).expect("seat 0").hand = vec![crate::SolutionCard { suit }];
|
|
||||||
assert_eq!(
|
|
||||||
solvable(&st, PlayerId(0)),
|
|
||||||
vec![n],
|
|
||||||
"fixture is not solvable"
|
|
||||||
);
|
|
||||||
(st, n)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// **Which layer enforces GR-P05**, pinned so it cannot drift.
|
|
||||||
///
|
|
||||||
/// All four conditions live in `validate`, and `legal_commands` gets
|
|
||||||
/// them for free by filtering candidates through it. This test is what
|
|
||||||
/// keeps that true: if `validate` ever stops rejecting one, SOLVE
|
|
||||||
/// becomes offerable again and the offer layer would have to grow a
|
|
||||||
/// filter back.
|
|
||||||
#[test]
|
|
||||||
fn validate_enforces_all_four_solve_conditions() {
|
|
||||||
let (base, n) = solvable_fixture();
|
|
||||||
let sel = |p: u32| GroundCommand::SelectAction {
|
|
||||||
action: Action::Solve,
|
|
||||||
target: None,
|
|
||||||
problem: Some(p),
|
|
||||||
};
|
|
||||||
let ok =
|
|
||||||
|st: &GroundState, p: u32| st.validate(Actor::Player(PlayerId(0)), &sel(p)).is_ok();
|
|
||||||
|
|
||||||
let face_down = *base
|
|
||||||
.problems
|
|
||||||
.iter()
|
|
||||||
.find(|(_, p)| !p.face_up)
|
|
||||||
.map(|(k, _)| k)
|
|
||||||
.expect("a face-down problem");
|
|
||||||
println!(
|
|
||||||
" validate accepts SOLVE on face-down: {}",
|
|
||||||
ok(&base, face_down)
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut denied = base.clone();
|
|
||||||
denied.problems.get_mut(&n).unwrap().denied = true;
|
|
||||||
println!(" validate accepts SOLVE on denied: {}", ok(&denied, n));
|
|
||||||
|
|
||||||
let mut claimed = base.clone();
|
|
||||||
claimed.problems.get_mut(&n).unwrap().claimed_by = Some(PlayerId(1));
|
|
||||||
println!(
|
|
||||||
" validate accepts SOLVE on claimed: {}",
|
|
||||||
ok(&claimed, n)
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut nohand = base.clone();
|
|
||||||
nohand.players.get_mut(&PlayerId(0)).unwrap().hand = vec![];
|
|
||||||
println!(" validate accepts SOLVE with no hand: {}", ok(&nohand, n));
|
|
||||||
|
|
||||||
// validate's: adding these to `legal_commands` would be dead code.
|
|
||||||
for (what, accepted) in [
|
|
||||||
("face-down", ok(&base, face_down)),
|
|
||||||
("Denied", ok(&denied, n)),
|
|
||||||
("claimed", ok(&claimed, n)),
|
|
||||||
("handless", ok(&nohand, n)),
|
|
||||||
] {
|
|
||||||
assert!(
|
|
||||||
!accepted,
|
|
||||||
"validate accepts SOLVE on a {what} Problem — GR-P05 is not \
|
|
||||||
enforced where rules live, so only clients that ask what is \
|
|
||||||
legal would be constrained"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
// Positive control: the fixture must still be solvable, or this
|
|
||||||
// test would pass by rejecting everything.
|
|
||||||
assert!(ok(&base, n), "the solvable fixture stopped being solvable");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// **The maintainer's reported case.** SOLVE was offered on a
|
|
||||||
/// face-down Problem and did nothing; they played it three rounds
|
|
||||||
/// running with no explanation. ground-game: *"not offered — illegal
|
|
||||||
/// target. Browser no-ops were a filter bug, not a bluff mechanic."*
|
|
||||||
#[test]
|
|
||||||
fn solve_is_not_offered_on_a_face_down_problem() {
|
|
||||||
let (st, open) = solvable_fixture();
|
|
||||||
let face_down: Vec<u32> = st
|
|
||||||
.problems
|
|
||||||
.iter()
|
|
||||||
.filter(|(_, p)| !p.face_up)
|
|
||||||
.map(|(n, _)| *n)
|
|
||||||
.collect();
|
|
||||||
assert!(!face_down.is_empty(), "GR-S01 deals face-down Problems");
|
|
||||||
let offered = solvable(&st, PlayerId(0));
|
|
||||||
for n in face_down {
|
|
||||||
assert!(
|
|
||||||
!offered.contains(&n),
|
|
||||||
"SOLVE offered on face-down problem {n}; offered = {offered:?}"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
assert!(offered.contains(&open), "the face-up one is still offered");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn solve_is_not_offered_without_a_matching_solution_in_hand() {
|
|
||||||
let (mut st, n) = solvable_fixture();
|
|
||||||
let wrong = [
|
|
||||||
crate::Suit::Clarify,
|
|
||||||
crate::Suit::Repair,
|
|
||||||
crate::Suit::Boundary,
|
|
||||||
crate::Suit::Change,
|
|
||||||
]
|
|
||||||
.into_iter()
|
|
||||||
.find(|s| *s != st.problems[&n].suit)
|
|
||||||
.expect("another suit exists");
|
|
||||||
st.players.get_mut(&PlayerId(0)).expect("seat 0").hand =
|
|
||||||
vec![crate::SolutionCard { suit: wrong }];
|
|
||||||
assert!(
|
|
||||||
!solvable(&st, PlayerId(0)).contains(&n),
|
|
||||||
"SOLVE offered with no matching Solution in hand"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn solve_is_not_offered_on_a_denied_problem() {
|
|
||||||
let (mut st, n) = solvable_fixture();
|
|
||||||
st.problems.get_mut(&n).expect("problem").denied = true;
|
|
||||||
assert!(
|
|
||||||
!solvable(&st, PlayerId(0)).contains(&n),
|
|
||||||
"SOLVE offered on a Denied Problem"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The ruling's (c): a Problem claimed in a PRIOR round is not
|
|
||||||
/// offered. At Select time every `claimed_by` is prior-round, because
|
|
||||||
/// claims land at Resolve — so the same-round race needs no code.
|
|
||||||
#[test]
|
|
||||||
fn solve_is_not_offered_on_an_already_claimed_problem() {
|
|
||||||
let (mut st, n) = solvable_fixture();
|
|
||||||
st.problems.get_mut(&n).expect("problem").claimed_by = Some(PlayerId(1));
|
|
||||||
assert!(
|
|
||||||
!solvable(&st, PlayerId(0)).contains(&n),
|
|
||||||
"SOLVE offered on an already-claimed Problem"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn policies(kind: &str, n: u8, seed: u64) -> Vec<Box<dyn Policy>> {
|
fn policies(kind: &str, n: u8, seed: u64) -> Vec<Box<dyn Policy>> {
|
||||||
(0..n)
|
(0..n)
|
||||||
.map(|i| -> Box<dyn Policy> {
|
.map(|i| -> Box<dyn Policy> {
|
||||||
|
|
|
||||||
|
|
@ -1756,28 +1756,6 @@ impl GroundState {
|
||||||
"GR-A13: Problem {problem} is not a face-up, non-Denied Problem"
|
"GR-A13: Problem {problem} is not a face-up, non-Denied Problem"
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
// GR-P05, ruled by ground-game 2026-08-03: SOLVE is legal
|
|
||||||
// only where it can do something. This lives in `validate`
|
|
||||||
// and not only in `legal_commands` because a rule enforced
|
|
||||||
// by the offer alone is enforced only for clients that ask
|
|
||||||
// what is legal — the browser would be filtered and a
|
|
||||||
// scenario file would not.
|
|
||||||
Action::Solve if target.claimed_by.is_some() => {
|
|
||||||
return Err(bad(format!(
|
|
||||||
"GR-P05: Problem {problem} was claimed in an earlier round"
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
Action::Solve
|
|
||||||
if !self
|
|
||||||
.players
|
|
||||||
.get(&actor)
|
|
||||||
.is_some_and(|p| p.hand.iter().any(|c| c.suit == target.suit)) =>
|
|
||||||
{
|
|
||||||
return Err(bad(format!(
|
|
||||||
"GR-P05: no {:?} Solution in hand for Problem {problem}",
|
|
||||||
target.suit
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
} else if problem.is_some() {
|
} else if problem.is_some() {
|
||||||
|
|
@ -2184,19 +2162,6 @@ mod replay_probe {
|
||||||
use cb_kernel::EventSeq;
|
use cb_kernel::EventSeq;
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
|
||||||
/// A fresh game at `seats` players, for the seat-count sweep.
|
|
||||||
fn fresh_n(seats: u8) -> GroundState {
|
|
||||||
GroundState::setup(
|
|
||||||
&Setup {
|
|
||||||
players: seats,
|
|
||||||
preset: format!("standard-{seats}p"),
|
|
||||||
patch: BTreeMap::new(),
|
|
||||||
},
|
|
||||||
42,
|
|
||||||
)
|
|
||||||
.expect("a standard deal")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fresh(seed: u64) -> GroundState {
|
fn fresh(seed: u64) -> GroundState {
|
||||||
GroundState::setup(
|
GroundState::setup(
|
||||||
&Setup {
|
&Setup {
|
||||||
|
|
@ -2476,60 +2441,6 @@ mod replay_probe {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// **GD-0001: group success is arithmetically unreachable below 5
|
|
||||||
/// seats**, and this is the reproduction rather than an argument.
|
|
||||||
///
|
|
||||||
/// The maintainer played several 3-player games on 2026-08-03 and
|
|
||||||
/// could not win any of them. This says why: claim *every* Problem
|
|
||||||
/// the deal puts in play, concede nothing, and the total still falls
|
|
||||||
/// short of GR-E01's threshold at 2, 3 and 4 seats.
|
|
||||||
///
|
|
||||||
/// It reads both numbers out of the engine — `problem_priorities`
|
|
||||||
/// (GR-S01's deal) and `threshold` (GR-E01) — so it cannot drift from
|
|
||||||
/// the rules it is testing, and it holds for **either dataset**: the
|
|
||||||
/// stand-in gives 3/6/10 and `Problems.csv` gives 4/6/9, against the
|
|
||||||
/// same 5/7/9.
|
|
||||||
///
|
|
||||||
/// **This test asserts the defect.** It is expected to keep passing
|
|
||||||
/// until ground-game rules, and to be inverted when it does — either
|
|
||||||
/// the deal count rises or the thresholds fall.
|
|
||||||
#[test]
|
|
||||||
fn gd0001_group_success_is_unreachable_below_five_seats() {
|
|
||||||
let mut verdicts = Vec::new();
|
|
||||||
for seats in 2..=6u8 {
|
|
||||||
let state = fresh_n(seats);
|
|
||||||
let best: u32 = state.problems.values().map(|p| u32::from(p.value)).sum();
|
|
||||||
let need = state.threshold();
|
|
||||||
verdicts.push((seats, state.problems.len(), best, need, best >= need));
|
|
||||||
println!(
|
|
||||||
" {seats}p: {} problem(s) worth {best} against a threshold of {need} \u{2014} {}",
|
|
||||||
state.problems.len(),
|
|
||||||
if best >= need {
|
|
||||||
"reachable"
|
|
||||||
} else {
|
|
||||||
"UNREACHABLE"
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
let unreachable: Vec<u8> = verdicts
|
|
||||||
.iter()
|
|
||||||
.filter(|(_, _, _, _, ok)| !ok)
|
|
||||||
.map(|(s, _, _, _, _)| *s)
|
|
||||||
.collect();
|
|
||||||
// Positive control: a run where everything is reachable would
|
|
||||||
// report a clean sheet and prove nothing.
|
|
||||||
assert!(
|
|
||||||
!verdicts.is_empty() && verdicts.iter().any(|(_, _, _, _, ok)| *ok),
|
|
||||||
"no seat count was reachable; the harness measured nothing useful"
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
unreachable,
|
|
||||||
vec![2, 3, 4],
|
|
||||||
"GD-0001 has changed: ground-game may have ruled. Re-read the \
|
|
||||||
finding before editing this test."
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// AM-7 scaling floor from GameKernel §5: fold throughput at 100k
|
/// AM-7 scaling floor from GameKernel §5: fold throughput at 100k
|
||||||
/// events must be at least this fraction of throughput at 5k.
|
/// events must be at least this fraction of throughput at 5k.
|
||||||
///
|
///
|
||||||
|
|
|
||||||
|
|
@ -1,160 +0,0 @@
|
||||||
---
|
|
||||||
id: CB-RES-0007
|
|
||||||
capability: design.findings
|
|
||||||
status: draft — awaiting adversarial review (CB-WP-0022 T02)
|
|
||||||
tier: L
|
|
||||||
chaos: d8 = 6 → no override
|
|
||||||
---
|
|
||||||
|
|
||||||
# CB-RES-0007 — how rigorous rule systems record the ambiguity they find
|
|
||||||
|
|
||||||
CB-WP-0022 T01. Surveyed 2026-08-03.
|
|
||||||
|
|
||||||
**Not a survey of issue trackers.** The question is narrower: when a
|
|
||||||
system is formal enough to *notice* that its rules do not decide
|
|
||||||
something, what does it do with that observation? Three practices, and
|
|
||||||
ourselves.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 1. The baseline is us, and it is measured
|
|
||||||
|
|
||||||
The external candidates are **practices, not runnable software**, so per
|
|
||||||
InnerLoop Step 1 their rows are **directional and cap at `parity`**. The
|
|
||||||
row that *can* be run is our own, and it is the one that matters, because
|
|
||||||
the register has to beat what we already do.
|
|
||||||
|
|
||||||
`tools/` harness output, 2026-08-03:
|
|
||||||
|
|
||||||
```
|
|
||||||
findings 6
|
|
||||||
with a runnable reproduction 2/6 = 33%
|
|
||||||
distinct files holding them 11
|
|
||||||
single register? NO — 11 files, no index
|
|
||||||
|
|
||||||
U1..U10: raised 2026-07-30, first READ 2026-08-03 — 4 days
|
|
||||||
U1..U10: answered? NO — 4+ days open, 0 of 10 ruled
|
|
||||||
```
|
|
||||||
|
|
||||||
| finding | locations | reproduction |
|
|
||||||
|---|---:|---|
|
|
||||||
| U1–U10 underdetermined points | 1 | — |
|
|
||||||
| SOLVE on a face-down Problem | 2 | — |
|
|
||||||
| GR-A13 wasted SOLVE | 1 | — |
|
|
||||||
| GR-E01 unreachable below 5 seats | 3 | **yes** (scenario) |
|
|
||||||
| six provisional defaults | 6 | **yes** (scenarios) |
|
|
||||||
| GR-E03/GR-E04 never played | 1 | — |
|
|
||||||
|
|
||||||
### The uncomfortable number, stated before anyone else finds it
|
|
||||||
|
|
||||||
**The rule the declaration proposed — *no finding without its
|
|
||||||
reproduction* — would reject four of our six existing findings.**
|
|
||||||
|
|
||||||
That is exactly the objection T02 is instructed to press, and the survey's
|
|
||||||
job is to answer it rather than route around it. The answer is that
|
|
||||||
**none of the four is expensive to reproduce**:
|
|
||||||
|
|
||||||
- *SOLVE on a face-down Problem* — a scenario selecting SOLVE on a
|
|
||||||
face-down Problem and asserting no claim follows. The engine already
|
|
||||||
produced the behaviour; nobody wrote it down.
|
|
||||||
- *GR-A13 wasted SOLVE* — the same shape.
|
|
||||||
- *GR-E03/E04 never played* — a bot game to completion in each mode,
|
|
||||||
which `bot::play` already does.
|
|
||||||
- *U1–U10* — six of the ten already have provisional scenarios; the
|
|
||||||
remaining four need the same treatment.
|
|
||||||
|
|
||||||
So the 33% is not evidence that reproductions are costly. **It is evidence
|
|
||||||
that nobody was ever asked for one**, which is the defect the register
|
|
||||||
exists to fix and not an argument against the rule.
|
|
||||||
|
|
||||||
## 2. Magic: the correction lands in the source, and the ruling is not authoritative
|
|
||||||
|
|
||||||
The most instructive practice, and it **corrected an assumption this pass
|
|
||||||
was about to build on**. I expected rulings to be the authoritative
|
|
||||||
resolution of an ambiguity. They are not.
|
|
||||||
|
|
||||||
The system is three layers, not two:
|
|
||||||
|
|
||||||
| layer | what it is | authoritative? |
|
|
||||||
|---|---|---|
|
|
||||||
| Comprehensive Rules | the general rules | yes |
|
|
||||||
| **Oracle** | the current authoritative text of each *card* — errata folded **in** | **yes** |
|
|
||||||
| Rulings (via Gatherer) | judge annotations attached to a card | **no** — *"reminder information with no actual weight or rules meaning"* |
|
|
||||||
|
|
||||||
When a card *"causes confusion, has outdated terminology, or doesn't work
|
|
||||||
as intended, the Oracle text may be updated"* — the fix goes **into the
|
|
||||||
authoritative text**, and the ruling layer stays explanatory.
|
|
||||||
|
|
||||||
**The property to steal: a finding closes when the source changes, not
|
|
||||||
when an annotation is added.** A register that accumulates permanent
|
|
||||||
rulings is a system that has given up on fixing its rules. Ours should be
|
|
||||||
a **queue that empties**, not an archive that grows.
|
|
||||||
|
|
||||||
This directly shapes the lifecycle in T03: `applied` must mean *the rules
|
|
||||||
text or the dataset changed and our provisional default was deleted* — not
|
|
||||||
*a ruling was recorded*.
|
|
||||||
|
|
||||||
*Directional, cited-only: the practice is described, not benchmarked.*
|
|
||||||
|
|
||||||
## 3. Model checkers: the counterexample IS the finding
|
|
||||||
|
|
||||||
A model checker does not report *"this property may not hold."* It emits a
|
|
||||||
**counterexample trace** — a concrete execution that violates the claim,
|
|
||||||
replayable by the tool that produced it.
|
|
||||||
|
|
||||||
That is precisely the shape the declaration proposed, arrived at
|
|
||||||
independently, and it is the strongest argument for the reproduction rule:
|
|
||||||
in formal methods a claim without a trace is not a result, it is a
|
|
||||||
hypothesis. Our `gr-e01-threshold-unreachable-2p` scenario is a
|
|
||||||
counterexample in exactly this sense — it is a failing-in-fact artifact
|
|
||||||
rather than a paragraph, and CB-EV-0005 already refused to delete it for
|
|
||||||
that reason.
|
|
||||||
|
|
||||||
**Property to beat: 100% of findings carry a replayable artifact.**
|
|
||||||
|
|
||||||
*Directional, cited-only.*
|
|
||||||
|
|
||||||
## 4. W3C / WHATWG: naming the undecided so it cannot be silently decided
|
|
||||||
|
|
||||||
Specifications mark points as *implementation-defined* or
|
|
||||||
*implementation-dependent*, which does two things at once: it tells an
|
|
||||||
implementer they may choose, and it tells the *spec* that a choice is
|
|
||||||
outstanding. The mark is machine-findable and survives revisions.
|
|
||||||
|
|
||||||
We already have this and it works: `provisional: true` +
|
|
||||||
`provisional_owner` on a scenario, surfaced by `make coverage` with an
|
|
||||||
age. It is the one piece of the machinery that is not missing.
|
|
||||||
|
|
||||||
**The register must reuse it, not compete with it.** Six of our findings
|
|
||||||
already live there; a second mechanism would immediately disagree with the
|
|
||||||
first.
|
|
||||||
|
|
||||||
*Directional, cited-only.*
|
|
||||||
|
|
||||||
## 5. Benchmarks to beat
|
|
||||||
|
|
||||||
| dimension | today | benchmark |
|
|
||||||
|---|---|---|
|
|
||||||
| **findability** | 11 files, no index | **one register with an index**; every finding reachable from one command |
|
|
||||||
| **reproducibility** | **2/6 = 33%** | **100%**, with withdrawn findings kept in the denominator |
|
|
||||||
| **closure** | 0 of 10 U-items ruled in 4+ days | a finding closes only when **the source changed** (Magic's Oracle property), and the register says which commit |
|
|
||||||
| **time raised → read** | **4 days** | the number this exists to fix; any mechanism that does not move it has failed |
|
|
||||||
| **taxonomy fits reality** | untested | all six existing findings expressible **without** a new kind being invented during backfill |
|
|
||||||
|
|
||||||
## 6. What the survey did not settle
|
|
||||||
|
|
||||||
- **Whether a finding without a reproduction is rejected or admitted as a
|
|
||||||
note.** §1 shows the rule is affordable for our six, but that is n=6 and
|
|
||||||
all six are *engine-surfaced*. A finding from **play** — *"the DARVO
|
|
||||||
sequence feels punishing at 2 players"* — may be real and have no cheap
|
|
||||||
artifact. T03 must decide, and the honest options are a `note` tier that
|
|
||||||
can never be reported as a finding, or refusal.
|
|
||||||
- **Where the register lives.** A finding is about *ground-game's* rules
|
|
||||||
but is produced by *clay-borg*. Putting it only in clay-borg repeats the
|
|
||||||
unread-inbox failure; putting it only in ground-game separates it from
|
|
||||||
its reproduction. Not decided here.
|
|
||||||
- **Whether the engine-evolution register is redundant.** The
|
|
||||||
declaration's judgment is that it is. This survey found nothing that
|
|
||||||
bears on it either way, which is itself worth saying: the practices
|
|
||||||
above are all about *rules*, and none of them is about how the tool that
|
|
||||||
found the problem evolved.
|
|
||||||
|
|
@ -1,48 +0,0 @@
|
||||||
scenario: ground/gr-p05-solve-legality
|
|
||||||
description: >
|
|
||||||
GR-P05, ruled by ground-game 2026-08-03: SOLVE is legal only where it
|
|
||||||
can do something. P1 holds no Clarify and is refused Problem 1; P2
|
|
||||||
holds one, is admitted, and claims it.
|
|
||||||
|
|
||||||
The prior-round-claim half of GR-P05 is asserted in
|
|
||||||
`bot::tests::validate_enforces_all_four_solve_conditions` rather than
|
|
||||||
here, because reaching a second round costs a dozen commands to test
|
|
||||||
one rejection.
|
|
||||||
|
|
||||||
The rule is asserted here rather than only in `legal_commands`, because
|
|
||||||
a rule enforced by the offer alone constrains only clients that ask what
|
|
||||||
is legal — a scenario file would walk straight past it. That is what the
|
|
||||||
AM-1 coverage gate surfaced when GR-P05 was added with no scenario.
|
|
||||||
covers: [GR-P05, GR-A02, GR-P03]
|
|
||||||
provisional: false
|
|
||||||
seed: 42
|
|
||||||
setup:
|
|
||||||
players: 3
|
|
||||||
preset: standard-3p
|
|
||||||
patch:
|
|
||||||
"lead": 1
|
|
||||||
"players.0.hand": [{ suit: Change }]
|
|
||||||
"players.1.hand": [{ suit: Clarify }]
|
|
||||||
commands:
|
|
||||||
# 0 — P1 holds no Clarify: refused.
|
|
||||||
- actor: P1
|
|
||||||
cmd: select_action
|
|
||||||
args: { action: SOLVE, problem: 1 }
|
|
||||||
# 1 — P2 holds one: admitted.
|
|
||||||
- actor: P2
|
|
||||||
cmd: select_action
|
|
||||||
args: { action: SOLVE, problem: 1 }
|
|
||||||
- actor: P1
|
|
||||||
cmd: select_action
|
|
||||||
args: { action: INVESTIGATE, problem: 2 }
|
|
||||||
- actor: P3
|
|
||||||
cmd: select_action
|
|
||||||
args: { action: INVESTIGATE, problem: 3 }
|
|
||||||
- actor: SYSTEM
|
|
||||||
cmd: reveal
|
|
||||||
- actor: SYSTEM
|
|
||||||
cmd: resolve
|
|
||||||
expect:
|
|
||||||
rejects: [0]
|
|
||||||
state:
|
|
||||||
"problems.1.claimed_by": 1
|
|
||||||
|
|
@ -177,17 +177,6 @@ terms.
|
||||||
printed value for scoring; a Problem can be claimed at most once.
|
printed value for scoring; a Problem can be claimed at most once.
|
||||||
- **GR-P04** Competing SOLVEs on the same Problem in the same round
|
- **GR-P04** Competing SOLVEs on the same Problem in the same round
|
||||||
resolve in Lead order (GR-R07); losers keep their Solution (GR-A02).
|
resolve in Lead order (GR-R07); losers keep their Solution (GR-A02).
|
||||||
- **GR-P05** *(ruled by ground-game 2026-08-03, GROUND-WP-0002 T02)*
|
|
||||||
**SOLVE is offered only where it can do something.** A seat may select
|
|
||||||
SOLVE on a Problem only if it is face-up, non-Denied, **unclaimed**, and
|
|
||||||
the seat **holds a Solution of the required suit**. A Problem claimed in
|
|
||||||
a *prior* round is not a legal target; the same-round race of GR-P04 is
|
|
||||||
unaffected, because both seats select before either resolves.
|
|
||||||
|
|
||||||
*Not a bluff mechanic.* CB-WP-0018 raised the possibility that
|
|
||||||
selecting an unfulfillable SOLVE was an intended face-down bluff. The
|
|
||||||
ruling is that it was a filter bug: *"the player always knows their
|
|
||||||
hand… physical tables self-police the same way."*
|
|
||||||
|
|
||||||
## 9. Protection, Focus and Blame (GR-T)
|
## 9. Protection, Focus and Blame (GR-T)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -87,8 +87,8 @@ rule 4).
|
||||||
a rule a scenario claims should also appear in the aggregate source, or
|
a rule a scenario claims should also appear in the aggregate source, or
|
||||||
the claim rests on a tag and nothing else.
|
the claim rests on a tag and nothing else.
|
||||||
|
|
||||||
Measured 2026-08-04: **50 of 59** claimed rules are named in <!-- fact:gr_linked --><!-- fact:gr_rules -->
|
Measured 2026-07-31: **49 of 58** claimed rules are named in <!-- fact:gr_linked --><!-- fact:gr_rules -->
|
||||||
`games/ground/src/lib.rs`. **Unmet**, target 59. The nine unlinked:
|
`games/ground/src/lib.rs`. **Unmet**, target 58. The nine unlinked:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
GR-D07 GR-F02 GR-L03 GR-O03 GR-P01 GR-P02 GR-P03 GR-P04 GR-T01
|
GR-D07 GR-F02 GR-L03 GR-O03 GR-P01 GR-P02 GR-P03 GR-P04 GR-T01
|
||||||
|
|
|
||||||
|
|
@ -1,93 +0,0 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
"""Baseline harness: how findable, reproducible and answered are the
|
|
||||||
design findings this project has already produced?
|
|
||||||
|
|
||||||
The comparator is US, today. The external candidates (rulings databases,
|
|
||||||
model-checker traces, W3C provisional marks) are practices rather than
|
|
||||||
runnable software, so per InnerLoop Step 1 their rows are DIRECTIONAL and
|
|
||||||
cap at `parity`. This is the row that can be measured.
|
|
||||||
"""
|
|
||||||
import os, re, subprocess, sys, datetime
|
|
||||||
|
|
||||||
ROOT = "/home/worsch/clay-borg"
|
|
||||||
os.chdir(ROOT)
|
|
||||||
|
|
||||||
# The findings this project has actually produced, and where each lives.
|
|
||||||
FINDINGS = {
|
|
||||||
"U1..U10 underdetermined points": ["specs/GroundRules.md"],
|
|
||||||
"SOLVE on a face-down Problem": ["workplans/CB-WP-0018-the-browser-is-a-client.md",
|
|
||||||
"evidence/CB-EV-0016-the-browser-is-a-client.md"],
|
|
||||||
"GR-A13 wasted SOLVE": ["evidence/CB-EV-0007-stage-0.md"],
|
|
||||||
"GR-E01 unreachable below 5 seats": ["evidence/CB-EV-0007-stage-0.md",
|
|
||||||
"scenarios/ground/gr-e01-threshold-unreachable-2p.yaml",
|
|
||||||
"workplans/CB-WP-0021-import-the-edition.md"],
|
|
||||||
"six provisional defaults": sorted(
|
|
||||||
os.path.join("scenarios/ground", f)
|
|
||||||
for f in os.listdir("scenarios/ground")
|
|
||||||
if f.endswith(".yaml")
|
|
||||||
and "provisional: true" in open(os.path.join("scenarios/ground", f)).read()),
|
|
||||||
"GR-E03/GR-E04 never played": ["evidence/CB-EV-0007-stage-0.md"],
|
|
||||||
}
|
|
||||||
|
|
||||||
def has_reproduction(paths):
|
|
||||||
"""A runnable thing: a scenario file, or a named test/command."""
|
|
||||||
for p in paths:
|
|
||||||
if p.startswith("scenarios/"):
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
def self_test():
|
|
||||||
"""The control that matters: a harness that read nothing must not
|
|
||||||
report a clean baseline. Every path this survey cites must exist, and
|
|
||||||
the reproduction test must be able to say NO — one that answered yes
|
|
||||||
for everything would report 100% and look excellent."""
|
|
||||||
results = []
|
|
||||||
|
|
||||||
def check(name, ok, detail=""):
|
|
||||||
results.append((name, ok, detail))
|
|
||||||
|
|
||||||
missing = [p for paths in FINDINGS.values() for p in paths
|
|
||||||
if not os.path.exists(p)]
|
|
||||||
check("every cited location exists", not missing, ", ".join(missing[:3]))
|
|
||||||
check("the finding set is not empty", len(FINDINGS) >= 6, f"{len(FINDINGS)}")
|
|
||||||
check("reproduction detection can say NO",
|
|
||||||
not has_reproduction(["evidence/CB-EV-0007-stage-0.md"]),
|
|
||||||
"a detector that always says yes would report 100%")
|
|
||||||
check("reproduction detection can say YES",
|
|
||||||
has_reproduction(["scenarios/ground/gr-e01-threshold-unreachable-2p.yaml"]))
|
|
||||||
# The number this survey turns on, pinned so a later edit cannot move
|
|
||||||
# it silently: 2 of 6 today.
|
|
||||||
repro_now = sum(has_reproduction(v) for v in FINDINGS.values())
|
|
||||||
check("the measured baseline is 2 of 6", repro_now == 2, f"{repro_now}/6")
|
|
||||||
|
|
||||||
print("design-baseline self-test (positive control)")
|
|
||||||
ok = True
|
|
||||||
for name, passed, det in results:
|
|
||||||
print(f" [{'ok ' if passed else 'FAIL'}] {name}" + (f" — {det}" if det else ""))
|
|
||||||
ok &= passed
|
|
||||||
return 0 if ok else 1
|
|
||||||
|
|
||||||
|
|
||||||
if "--self-test" in sys.argv:
|
|
||||||
raise SystemExit(self_test())
|
|
||||||
|
|
||||||
print("BASELINE — design findings as they stand, 2026-08-03\n")
|
|
||||||
places = set()
|
|
||||||
repro = 0
|
|
||||||
for name, paths in FINDINGS.items():
|
|
||||||
places.update(paths)
|
|
||||||
r = has_reproduction(paths)
|
|
||||||
repro += r
|
|
||||||
print(f" {'repro' if r else ' - '} {len(paths)} location(s) {name}")
|
|
||||||
|
|
||||||
n = len(FINDINGS)
|
|
||||||
print(f"\n findings {n}")
|
|
||||||
print(f" with a runnable reproduction {repro}/{n} = {100*repro//n}%")
|
|
||||||
print(f" distinct files holding them {len(places)}")
|
|
||||||
print(f" single register? NO — {len(places)} files, no index")
|
|
||||||
|
|
||||||
# Time from raised to READ, for the one finding with a timestamp trail.
|
|
||||||
raised = datetime.date(2026, 7, 30) # hub message from clay-borg-custodian
|
|
||||||
read = datetime.date(2026, 8, 3) # marked read this session
|
|
||||||
print(f"\n U1..U10: raised {raised}, first READ {read} — {(read-raised).days} days")
|
|
||||||
print(f" U1..U10: answered? NO — {(read-raised).days}+ days open, 0 of 10 ruled")
|
|
||||||
|
|
@ -1,189 +0,0 @@
|
||||||
---
|
|
||||||
id: CB-WP-0021
|
|
||||||
kind: product
|
|
||||||
title: "Import the edition: the game plays its own data"
|
|
||||||
status: ready
|
|
||||||
---
|
|
||||||
|
|
||||||
# Purpose
|
|
||||||
|
|
||||||
```
|
|
||||||
structural tier M (adds or refuses an external dependency, and changes
|
|
||||||
how a game is set up — a canonical interface)
|
|
||||||
chaos d8 = 7 → no override
|
|
||||||
declared tier M
|
|
||||||
```
|
|
||||||
|
|
||||||
Declaration 4 of chaos window 2.
|
|
||||||
|
|
||||||
## The engine has been playing a stand-in
|
|
||||||
|
|
||||||
`games/ground/src/lib.rs` builds Problems with `value: priority` and suits
|
|
||||||
cycled by index. `editions/ground-darvo-r0/Problems.csv` has carried the
|
|
||||||
real thing since 2026-07-31, and **GROUND-WP-0002 T01 ruled it
|
|
||||||
authoritative on 2026-08-03**:
|
|
||||||
|
|
||||||
| | problems/scenario | values | total | suits |
|
|
||||||
|---|---:|---|---:|---|
|
|
||||||
| `Problems.csv` | **5** | 2, 2, 2, 3, 3 | **12** | `required_solution` per problem |
|
|
||||||
| the stand-in | 3 | 1, 2, 3 | **6** | cycled by index |
|
|
||||||
|
|
||||||
## CORRECTION, before any code: the import does not fix GR-E01
|
|
||||||
|
|
||||||
**This declaration opened by claiming it would, and the data says
|
|
||||||
otherwise.** The claim was *"ordinary against 12, unreachable against 6 —
|
|
||||||
it was never a rules gap."* Measured across all four scenarios:
|
|
||||||
|
|
||||||
**GR-S01 deals 2 / 3 / 4 problems by player count, not all five.** So the
|
|
||||||
points actually in play are never 12:
|
|
||||||
|
|
||||||
| players | dealt | available | GR-E01 threshold | |
|
|
||||||
|---:|---:|---:|---:|---|
|
|
||||||
| 2 | 2 | **4** | 5 | unreachable |
|
|
||||||
| 3–4 | 3 | **6** | 7 | unreachable |
|
|
||||||
| 5–6 | 4 | **9** | 9 | reachable, exactly |
|
|
||||||
|
|
||||||
Identical in shape to the stand-in, which gave 3 / 6 / 10 against the same
|
|
||||||
5 / 7 / 9. **So `GR-E01 unreachable below 5 seats` is a real property of
|
|
||||||
the game, not an artifact of the stand-in**, and
|
|
||||||
`gr-e01-threshold-unreachable-2p` is asserting something true.
|
|
||||||
|
|
||||||
The error was mine and it was the cheap kind to make: 12 points exist in
|
|
||||||
the file, so I assumed 12 points are in play. **One command over the CSV
|
|
||||||
settled it, and it was not run until after the declaration was
|
|
||||||
committed** — the characteristic error of this project, in the pass that
|
|
||||||
followed a ruling obtained *because* of it.
|
|
||||||
|
|
||||||
**CB-EV-0018 is corrected too.** It said the `0` scores were *"confirmed
|
|
||||||
as the stand-in's doing, not a scoring bug."* Overstated: the zero came
|
|
||||||
from no Problem being claimed at all, and the threshold gap is
|
|
||||||
independent of which dataset is loaded.
|
|
||||||
|
|
||||||
**What this changes.** The import is still right — the suits, values and
|
|
||||||
visibility are authoritative and the engine should stop inventing them.
|
|
||||||
But it resolves nothing about GR-E01, and T03 must send ground-game a
|
|
||||||
*sharper* question rather than a retirement: **either GR-S01's deal count
|
|
||||||
is wrong or GR-E01's thresholds are, and no dataset can reconcile them.**
|
|
||||||
|
|
||||||
## The constraint, measured before declaring
|
|
||||||
|
|
||||||
**AM-4a has 3,798 lines of headroom.** A CSV crate costs, marginally
|
|
||||||
against the shipped graph:
|
|
||||||
|
|
||||||
| crate | lines |
|
|
||||||
|---|---:|
|
|
||||||
| `csv` | 14,291 |
|
|
||||||
| `csv-core` | 3,360 |
|
|
||||||
| `ryu` | 3,962 |
|
|
||||||
| **marginal total** | **21,613** |
|
|
||||||
|
|
||||||
**5.7× the available headroom.** `itoa`, `memchr`, `serde` and
|
|
||||||
`serde_core` are already present and cost nothing; the parser itself is
|
|
||||||
what does not fit.
|
|
||||||
|
|
||||||
So the shipped runtime cannot gain a CSV parser, and that is settled by
|
|
||||||
measurement rather than by preference. What remains is *which* of the
|
|
||||||
alternatives to take, and that is the ADR.
|
|
||||||
|
|
||||||
## Task: decide how the data reaches the game
|
|
||||||
|
|
||||||
```task
|
|
||||||
id: CB-WP-0021-T01
|
|
||||||
status: todo
|
|
||||||
priority: high
|
|
||||||
```
|
|
||||||
|
|
||||||
Write `decisions/ADR-0011-*.md` (tier M: survey and decision in one).
|
|
||||||
|
|
||||||
**Three questions, and the third is the one that bites.**
|
|
||||||
|
|
||||||
**(a) Where does the data live?** `ground-game` is a separate repository.
|
|
||||||
Depending on a sibling checkout makes the build depend on a path that may
|
|
||||||
not exist; vendoring a copy makes clay-borg carry content it does not own.
|
|
||||||
Whichever is chosen must say how a copy is known to be current, because a
|
|
||||||
silently stale copy is worse than no copy.
|
|
||||||
|
|
||||||
**(b) How is it parsed, given a CSV parser does not fit?** Candidates, and
|
|
||||||
each needs its marginal cost stated rather than assumed:
|
|
||||||
- hand-rolled reader in `games/ground` — small, but it is a parser we
|
|
||||||
then own, and `problem_text` contains commas;
|
|
||||||
- **bake it**: a dev-time step converts the CSV into a generated Rust
|
|
||||||
module or compact literal, so the shipped runtime parses **nothing**.
|
|
||||||
Then the generated artifact must be proven to match its source, which
|
|
||||||
is the DFD class this repo already has machinery for;
|
|
||||||
- load nothing at runtime and treat the data as scenario input.
|
|
||||||
|
|
||||||
**(c) What does this do to determinism?** Problem values and required
|
|
||||||
suits become part of `GroundState`, which is hashed (K7). **Every recorded
|
|
||||||
state hash changes.** Before writing code, establish what actually pins a
|
|
||||||
hash today — `make sim` runs 25 scenarios, `replay-test` re-executes
|
|
||||||
bundles, and AM-7's probe asserts per-segment hashes. Say which of those
|
|
||||||
break, and whether any of them are *supposed* to be stable across a
|
|
||||||
content change.
|
|
||||||
|
|
||||||
**This is the reason the ADR exists.** A content import that quietly
|
|
||||||
invalidates every recorded hash, in a project whose central invariant is
|
|
||||||
replay determinism, is not a data-loading change.
|
|
||||||
|
|
||||||
## Task: import it, and let the thresholds mean something
|
|
||||||
|
|
||||||
```task
|
|
||||||
id: CB-WP-0021-T02
|
|
||||||
status: todo
|
|
||||||
priority: high
|
|
||||||
```
|
|
||||||
|
|
||||||
Replace the stand-in. `setup` must build Problems from the edition data:
|
|
||||||
`point_value`, `required_solution`, `visibility` (Surface → face up,
|
|
||||||
Hidden → face down) and `hidden_priority`.
|
|
||||||
|
|
||||||
**Controls:**
|
|
||||||
- **The stand-in must become unreachable.** A test that the fixture
|
|
||||||
constants no longer appear — a `value: priority` that survives beside
|
|
||||||
real data is a fallback nobody will notice until the numbers look odd
|
|
||||||
again.
|
|
||||||
- **A scenario must be able to reach GR-E01's threshold at 2 players**,
|
|
||||||
which is the specific thing that was impossible. Assert the arithmetic,
|
|
||||||
not just that a game runs.
|
|
||||||
- The 5-problem shape must survive: the stand-in dealt 3, and code that
|
|
||||||
assumed 3 will not announce itself.
|
|
||||||
|
|
||||||
## Task: retire the rules gap that was never one
|
|
||||||
|
|
||||||
```task
|
|
||||||
id: CB-WP-0021-T03
|
|
||||||
status: todo
|
|
||||||
priority: medium
|
|
||||||
```
|
|
||||||
|
|
||||||
`gr-e01-threshold-unreachable-2p` is tagged `provisional: true` with
|
|
||||||
`provisional_owner: ground-game`, and its description says group success
|
|
||||||
*"is unreachable at 2, 3 and 4 players"*. If T02 lands, that scenario is
|
|
||||||
asserting a property of the **stand-in**, not of the game.
|
|
||||||
|
|
||||||
Retire or rewrite it, and **say which of the six provisional items this
|
|
||||||
resolves**, so GROUND-WP-0002 T03 shrinks rather than being left to
|
|
||||||
rediscover it. Message `ground-game` with the outcome — the last such
|
|
||||||
message sat unread for four days because nothing pointed at it.
|
|
||||||
|
|
||||||
Do **not** quietly delete a failing-in-fact scenario. CB-EV-0005: *a score
|
|
||||||
improved by deleting the question is not an improvement.*
|
|
||||||
|
|
||||||
## Task: evidence
|
|
||||||
|
|
||||||
```task
|
|
||||||
id: CB-WP-0021-T04
|
|
||||||
status: todo
|
|
||||||
priority: high
|
|
||||||
```
|
|
||||||
|
|
||||||
`evidence/CB-EV-0019-*.md`.
|
|
||||||
|
|
||||||
- **What the import cost**, against the 3,798 lines that were available.
|
|
||||||
- **What broke**, especially hashes, and whether the blast radius was
|
|
||||||
predicted in T01 or discovered in T02. If it was discovered, say so —
|
|
||||||
that is the ADR having missed something.
|
|
||||||
- **Whether the endings now mean anything**: play one and report the
|
|
||||||
score against the threshold.
|
|
||||||
- **Quote CB-WP-0020's cost by re-running the instrument.**
|
|
||||||
- **Chaos: 4 of 12 in window 2.**
|
|
||||||
|
|
@ -1,271 +0,0 @@
|
||||||
---
|
|
||||||
id: CB-WP-0022
|
|
||||||
kind: product
|
|
||||||
title: "The design instrument: findings about the game, with their reproductions"
|
|
||||||
status: active
|
|
||||||
---
|
|
||||||
|
|
||||||
# Purpose
|
|
||||||
|
|
||||||
```
|
|
||||||
structural tier L (named a high-leverage pass by the maintainer, and it
|
|
||||||
amends INTENT — clay-borg gains a stated aspect)
|
|
||||||
chaos d8 = 6 → no override
|
|
||||||
declared tier L
|
|
||||||
```
|
|
||||||
|
|
||||||
Declaration 5 of chaos window 2. Tier L: separate survey, **adversarial
|
|
||||||
review**, ADR, then spec, then code.
|
|
||||||
|
|
||||||
## The insight, in the maintainer's words
|
|
||||||
|
|
||||||
> *"We should consider ourselves testing the game and document
|
|
||||||
> inconsistencies to report them back to the ground-game repo, so that the
|
|
||||||
> game designer can improve the rules accordingly… We should have the
|
|
||||||
> rigorous game simulation engine and a meta scope to capture notes about
|
|
||||||
> game design flaws, questions, results and protocols about trial games…
|
|
||||||
> This will provide clay-borg an additional aspect as a valuable game
|
|
||||||
> design tool."*
|
|
||||||
|
|
||||||
**This is already happening and has no home.** In five passes the engine
|
|
||||||
has produced, as a by-product of being rigorous:
|
|
||||||
|
|
||||||
| finding | how it surfaced |
|
|
||||||
|---|---|
|
|
||||||
| ten underdetermined rules points (U1–U10) | formalizing the dataset into testable rules |
|
|
||||||
| SOLVE offered on a face-down Problem, always inert | a human dragging it three rounds running |
|
|
||||||
| GR-A13 "wasted SOLVE" on a claimed Problem | a scenario that had to pick a default |
|
|
||||||
| GR-E01 unreachable below 5 seats | arithmetic over the deal count |
|
|
||||||
| six provisional scenario defaults | scenarios that could not be written without deciding something |
|
|
||||||
| GR-E03 / GR-E04 never played to the end | nobody noticed for nineteen passes |
|
|
||||||
|
|
||||||
Every one was found by *building the simulator*, not by playing. That is
|
|
||||||
the thing worth naming: **a simulator rigorous enough to refuse ambiguity
|
|
||||||
is a design instrument, because it cannot proceed past a rule that does
|
|
||||||
not decide.**
|
|
||||||
|
|
||||||
And every one of them has been carried in prose, in six different places,
|
|
||||||
and one sat unread in an inbox for four days.
|
|
||||||
|
|
||||||
## The load-bearing rule this must have
|
|
||||||
|
|
||||||
The project's standing failure is *unexecuted verification*. A design
|
|
||||||
register that collects opinions would reproduce it in a new medium.
|
|
||||||
|
|
||||||
> **A design finding is not admissible without its reproduction.**
|
|
||||||
|
|
||||||
Concretely: a scenario that fails, an arithmetic check that prints the
|
|
||||||
contradiction, a recorded game the reader can replay, or a named test.
|
|
||||||
*"This feels unbalanced"* is a note, not a finding. **GR-E01 is admissible
|
|
||||||
because 4/6/9 against 5/7/9 is a computation anyone can rerun; the SOLVE
|
|
||||||
inertness is admissible because a recorded session shows three no-ops.**
|
|
||||||
|
|
||||||
This is what would make clay-borg a design tool rather than a suggestion
|
|
||||||
box, and it is the one part of this proposal that must not be traded away
|
|
||||||
for convenience.
|
|
||||||
|
|
||||||
## The judgment I want reviewed, not assumed
|
|
||||||
|
|
||||||
The maintainer asked whether this should extend to *"a meta about the
|
|
||||||
clay-borg engine evolution itself."*
|
|
||||||
|
|
||||||
**My answer is no, and it should be argued rather than accepted.** That
|
|
||||||
register already exists and is load-bearing: `evidence/CB-EV-*` records
|
|
||||||
what each pass found, `decisions/ADR-*` records what was decided and what
|
|
||||||
was rejected, `gates.toml` records what every control has caught and what
|
|
||||||
would retire it, and workplans record what was attempted. Nineteen passes
|
|
||||||
of engine evolution are already captured, with dates, costs and
|
|
||||||
falsifiers.
|
|
||||||
|
|
||||||
**Building a second register for the same subject would be ceremony**, and
|
|
||||||
this project has a standing rule that a gate must cash out. The asymmetry
|
|
||||||
is the point: engine evolution has a home and game design does not.
|
|
||||||
|
|
||||||
If the adversarial review disagrees, that is exactly the kind of thing
|
|
||||||
tier L exists to surface.
|
|
||||||
|
|
||||||
## Task: survey how this is done elsewhere, and what we already have
|
|
||||||
|
|
||||||
```task
|
|
||||||
id: CB-WP-0022-T01
|
|
||||||
status: done
|
|
||||||
priority: high
|
|
||||||
```
|
|
||||||
|
|
||||||
`research/CB-RES-0007-*.md`.
|
|
||||||
|
|
||||||
**Do not survey issue trackers.** The question is narrower and more
|
|
||||||
interesting: how do rigorous rule systems record *the ambiguity they
|
|
||||||
found*? Candidates worth a benchmark-to-beat:
|
|
||||||
|
|
||||||
- **Errata and rulings practice** in published games (Magic's
|
|
||||||
comprehensive-rules + rulings split, Netrunner's NAPD card rulings) —
|
|
||||||
what makes a ruling *findable* years later.
|
|
||||||
- **Formal-methods counterexample traces** — a model checker's output is
|
|
||||||
precisely a reproduction attached to a claim, which is the shape wanted
|
|
||||||
here.
|
|
||||||
- **Conformance-suite provisional behaviour** — how W3C/WHATWG mark
|
|
||||||
"implementation-defined" and how a spec later absorbs it.
|
|
||||||
- **What this repo already has**: `provisional: true` scenarios,
|
|
||||||
`§Underdetermined`, `gates.toml`'s `caught`/`retire_if` shape, and the
|
|
||||||
hub message that went unread. **The register must reuse the provisional
|
|
||||||
machinery rather than compete with it.**
|
|
||||||
|
|
||||||
Name, per dimension, the property to beat — findability, reproducibility,
|
|
||||||
and whether a ruling can *close* a finding mechanically.
|
|
||||||
|
|
||||||
**Done 2026-08-03.**
|
|
||||||
[CB-RES-0007](../research/CB-RES-0007-design-instrument.md), with a
|
|
||||||
runnable baseline (`tools/design-baseline.py`).
|
|
||||||
|
|
||||||
**The baseline is us, and it is measured**: 6 findings across **11 files**
|
|
||||||
with no index, **2 of 6 (33%) with a runnable reproduction**, and U1–U10
|
|
||||||
raised 2026-07-30, first *read* 2026-08-03 — **4 days**, 0 of 10 ruled.
|
|
||||||
|
|
||||||
**The uncomfortable number is stated up front rather than left for the
|
|
||||||
review to find: the reproduction rule would reject four of our six
|
|
||||||
existing findings.** The survey answers it — none of the four is
|
|
||||||
expensive to reproduce, so the 33% is evidence that nobody was ever asked
|
|
||||||
for one, not that the rule is unaffordable.
|
|
||||||
|
|
||||||
**Magic corrected an assumption this pass was about to build on.** I
|
|
||||||
expected a ruling to be the authoritative resolution. It is not: rulings
|
|
||||||
are *"reminder information with no actual weight or rules meaning"*, and
|
|
||||||
the authoritative fix folds into the **Oracle** card text. **A finding
|
|
||||||
closes when the source changes, not when an annotation is added** — so
|
|
||||||
the register must be a queue that empties, not an archive that grows.
|
|
||||||
That is now a constraint on T03's lifecycle.
|
|
||||||
|
|
||||||
Model checkers supplied the reproduction rule independently (a
|
|
||||||
counterexample trace *is* the finding), and W3C's *implementation-defined*
|
|
||||||
mark is the one piece of machinery we already have and must reuse rather
|
|
||||||
than duplicate.
|
|
||||||
|
|
||||||
## Task: adversarial review
|
|
||||||
|
|
||||||
```task
|
|
||||||
id: CB-WP-0022-T02
|
|
||||||
status: todo
|
|
||||||
priority: high
|
|
||||||
```
|
|
||||||
|
|
||||||
Tier L requires it. Give the reviewer the survey **and** the §judgment
|
|
||||||
above, and require an attempt at:
|
|
||||||
|
|
||||||
- **that the engine-evolution register is redundant** — the strongest
|
|
||||||
counter is that ADRs record *decisions* and evidence records *findings*,
|
|
||||||
but nothing records *what we learned about building engines*, which is a
|
|
||||||
third thing;
|
|
||||||
- **that "carries its reproduction" is affordable** — if half the real
|
|
||||||
findings cannot be reproduced cheaply, the rule will be quietly dropped
|
|
||||||
and the register becomes a suggestion box anyway;
|
|
||||||
- **that a register is needed at all**, rather than one more section in
|
|
||||||
`GroundRules.md §Underdetermined`, which already exists and already
|
|
||||||
works.
|
|
||||||
|
|
||||||
Record the trail in `history/`, unpolished.
|
|
||||||
|
|
||||||
## Task: decide
|
|
||||||
|
|
||||||
```task
|
|
||||||
id: CB-WP-0022-T03
|
|
||||||
status: todo
|
|
||||||
priority: high
|
|
||||||
```
|
|
||||||
|
|
||||||
`decisions/ADR-0012-*.md`. At minimum:
|
|
||||||
|
|
||||||
- whether clay-borg's **INTENT gains a stated aspect** as a design
|
|
||||||
instrument, and in what words — this is the change with the longest
|
|
||||||
half-life in the pass;
|
|
||||||
- the finding **taxonomy**, and it should be grounded in the six findings
|
|
||||||
above rather than invented: *underdetermined* (rules do not say),
|
|
||||||
*inconsistent* (rules disagree with each other or the data), *inert* (a
|
|
||||||
rule that cannot fire), *degenerate* (fires, but collapses play),
|
|
||||||
*unplayed* (implemented, never played);
|
|
||||||
- the **lifecycle** and who owns each state: raised → reported → ruled →
|
|
||||||
applied, or withdrawn;
|
|
||||||
- whether a finding without a reproduction is **rejected** or **admitted
|
|
||||||
as a note** — and if admitted, how it is prevented from aging into an
|
|
||||||
apparent finding.
|
|
||||||
|
|
||||||
## Task: specify
|
|
||||||
|
|
||||||
```task
|
|
||||||
id: CB-WP-0022-T04
|
|
||||||
status: todo
|
|
||||||
priority: high
|
|
||||||
```
|
|
||||||
|
|
||||||
`specs/GameDesign.md`, with metrics, because a spec without them is prose.
|
|
||||||
|
|
||||||
Candidate measures, to be argued not adopted:
|
|
||||||
|
|
||||||
- **findings with a runnable reproduction** — target 100%, and the
|
|
||||||
denominator includes withdrawn ones;
|
|
||||||
- **time from raised to reported** — the U-items took four days to be
|
|
||||||
*read*; that is the number this exists to fix;
|
|
||||||
- **findings closed by a ruling** vs **findings still open**, with age.
|
|
||||||
|
|
||||||
Also specify the **trial protocol**, which is the part with no precedent
|
|
||||||
here: a trial game is a `--record`ed session plus an observation log, so
|
|
||||||
*"we played it and X happened"* is replayable rather than remembered. The
|
|
||||||
engine already records sessions as scenarios; a trial is that plus notes,
|
|
||||||
and it must cost almost nothing or it will not be done.
|
|
||||||
|
|
||||||
## Task: build it, and backfill what is already known
|
|
||||||
|
|
||||||
```task
|
|
||||||
id: CB-WP-0022-T05
|
|
||||||
status: todo
|
|
||||||
priority: high
|
|
||||||
```
|
|
||||||
|
|
||||||
The register, the tool, and then **the six findings above entered into
|
|
||||||
it** — backfilling is the test. A register that cannot express findings
|
|
||||||
the project already has is the wrong register, and discovering that after
|
|
||||||
designing it is the point of doing it in this order.
|
|
||||||
|
|
||||||
`make design` (or equivalent) must report: open findings by kind, those
|
|
||||||
without a reproduction, and those never reported to their owner.
|
|
||||||
|
|
||||||
## Task: report to ground-game, mechanically
|
|
||||||
|
|
||||||
```task
|
|
||||||
id: CB-WP-0022-T06
|
|
||||||
status: todo
|
|
||||||
priority: high
|
|
||||||
```
|
|
||||||
|
|
||||||
Generate the report and send it. **The message that sat unread for four
|
|
||||||
days is the baseline to beat**, and the failure was not the message — it
|
|
||||||
was that nothing pointed at it and nothing tracked whether it was
|
|
||||||
answered.
|
|
||||||
|
|
||||||
So the report must land somewhere that persists: a file in `ground-game`
|
|
||||||
under its own workplan, not only an inbox entry. GROUND-WP-0002 already
|
|
||||||
holds the ten U-items; this should extend it rather than duplicate it.
|
|
||||||
|
|
||||||
Include the two sharpened findings this pass has already produced:
|
|
||||||
|
|
||||||
- **GR-E01 vs GR-S01** — the deal count puts 4/6/9 points in play against
|
|
||||||
thresholds of 5/7/9, so either the count or the thresholds are wrong and
|
|
||||||
no dataset reconciles them;
|
|
||||||
- **SOLVE's legality** against a face-down Problem or an unmatchable suit.
|
|
||||||
|
|
||||||
## Task: evidence
|
|
||||||
|
|
||||||
```task
|
|
||||||
id: CB-WP-0022-T06B
|
|
||||||
status: todo
|
|
||||||
priority: high
|
|
||||||
```
|
|
||||||
|
|
||||||
`evidence/CB-EV-0020-*.md`.
|
|
||||||
|
|
||||||
- **Whether backfilling changed the design** — if all six findings fit the
|
|
||||||
first taxonomy, say so and be suspicious of it.
|
|
||||||
- **What tier L cost against what it caught**, since this is the second
|
|
||||||
full-weight L pass and CB-WP-0012's deleted its own structural trigger.
|
|
||||||
- **The engine-evolution question**, as the review left it.
|
|
||||||
- **Quote CB-WP-0021's cost by re-running the instrument.**
|
|
||||||
|
|
@ -1,134 +0,0 @@
|
||||||
---
|
|
||||||
id: CB-WP-0023
|
|
||||||
kind: product
|
|
||||||
title: "SOLVE is offered only where it can do something"
|
|
||||||
status: done
|
|
||||||
---
|
|
||||||
|
|
||||||
# Purpose
|
|
||||||
|
|
||||||
```
|
|
||||||
structural tier S (implements a ruling inside an existing capability —
|
|
||||||
no new port, no canonical interface, no dependency)
|
|
||||||
chaos d8 = 6 → no override
|
|
||||||
declared tier S
|
|
||||||
```
|
|
||||||
|
|
||||||
Declaration 6 of chaos window 2.
|
|
||||||
|
|
||||||
## A ruling, not a judgment call
|
|
||||||
|
|
||||||
`ground-game` ruled SOLVE's legality on 2026-08-03 (GROUND-WP-0002 T02),
|
|
||||||
after clay-borg raised it from play:
|
|
||||||
|
|
||||||
| sub | ruling |
|
|
||||||
|---|---|
|
|
||||||
| **(a)** face-down Problem | **Not offered — illegal target.** *"only face-up, non-Denied. Browser no-ops were a filter bug, not a bluff mechanic."* |
|
|
||||||
| **(b)** no matching Solution in hand | **Not offered.** *"the engine only offers SOLVE when a matching suit is held."* |
|
|
||||||
| **(c)** already-claimed Problem | **Same-round race legal; prior-round claim not offered.** |
|
|
||||||
|
|
||||||
**The bluff reading is dead.** CB-WP-0018 raised (a) as *possibly* an
|
|
||||||
intended bluff in a commit/reveal game and deferred to ground-game rather
|
|
||||||
than deciding. The answer is that it was a filter bug, and the engine has
|
|
||||||
been offering an inert move since the day `legal_commands` was written.
|
|
||||||
|
|
||||||
`legal_commands` offers Investigate and SOLVE on **every** problem key,
|
|
||||||
with no reference to `face_up`, `denied`, `claimed_by` or the hand.
|
|
||||||
|
|
||||||
**Only SOLVE is ruled on. Investigate is not touched** — implementing more
|
|
||||||
than was ruled would be inventing rules, which is what this whole exchange
|
|
||||||
exists to stop.
|
|
||||||
|
|
||||||
## Task: filter SOLVE to what the ruling allows
|
|
||||||
|
|
||||||
```task
|
|
||||||
id: CB-WP-0023-T01
|
|
||||||
status: done
|
|
||||||
priority: high
|
|
||||||
```
|
|
||||||
|
|
||||||
SOLVE is offered on problem `p` for seat `s` **iff** `p.face_up`,
|
|
||||||
`!p.denied`, `p.claimed_by.is_none()`, and `s`'s hand holds a card of
|
|
||||||
`p.suit`.
|
|
||||||
|
|
||||||
On (c): at Select time every `claimed_by` is from a prior round — claims
|
|
||||||
land at Resolve — so *"prior-round claim not offered"* is exactly
|
|
||||||
`claimed_by.is_none()`, and the same-round race is already legal because
|
|
||||||
both seats select before either resolves. **Say this in the code**, or the
|
|
||||||
next reader will add a round comparison that does nothing.
|
|
||||||
|
|
||||||
**Controls:**
|
|
||||||
- each of the four conditions must be independently mutation-provable —
|
|
||||||
drop one filter, and a test naming *that* condition goes red;
|
|
||||||
- the maintainer's reported case must be reproduced and then fixed: SOLVE
|
|
||||||
on a face-down Problem is offered before, not offered after;
|
|
||||||
- **`make sim` must still pass**, or the ruling has broken a scenario that
|
|
||||||
encoded the old behaviour — in which case the scenario was encoding a
|
|
||||||
bug and must be updated with a note, not quietly edited.
|
|
||||||
|
|
||||||
**Done 2026-08-04.** `make all` exits 0, 26 scenarios, rule coverage
|
|
||||||
**59/59**. **No scenario encoded the bug** — all 25 passed unchanged.
|
|
||||||
|
|
||||||
**The rule ended up somewhere other than where I put it, and a gate moved
|
|
||||||
it.** It went into `legal_commands` first. The AM-1 coverage gate then
|
|
||||||
demanded a scenario for the new GR-P05 — and scenarios drive `validate`,
|
|
||||||
not the offer layer. That is what showed the rule belonged in `validate`:
|
|
||||||
**a rule enforced only by the offer is enforced only for clients that ask
|
|
||||||
what is legal.** The browser would have been filtered and a scenario file
|
|
||||||
would have walked straight past it.
|
|
||||||
|
|
||||||
Once GR-P05 moved into `validate`, every condition in `legal_commands`
|
|
||||||
was dead code, and my own layering test said so in those words
|
|
||||||
(*"validate now rejects claimed — drop the filter"*). The offer layer is
|
|
||||||
back to one arm for Investigate and SOLVE together.
|
|
||||||
|
|
||||||
**And the reported case was not the one I reported.** CB-WP-0018 and the
|
|
||||||
message to ground-game described SOLVE offered on a **face-down** Problem.
|
|
||||||
Measured: `validate` already rejected face-down, so it never was offered.
|
|
||||||
Problem 1 is the Surface Problem and is face-up from the deal — the
|
|
||||||
maintainer's three inert SOLVEs were the **hand** case, holding no Clarify
|
|
||||||
for a Clarify Problem. The ruling covers both, so nothing is invalidated,
|
|
||||||
but the record was wrong and is corrected here.
|
|
||||||
|
|
||||||
Four conditions, each asserted separately, because one "SOLVE is filtered"
|
|
||||||
test would pass with three of four implemented. Mutations: dropping the
|
|
||||||
claimed filter and dropping the hand filter each turn their own test red;
|
|
||||||
inverting the layering assertion turns `validate_enforces_all_four` red.
|
|
||||||
|
|
||||||
## Task: retire what the ruling settles
|
|
||||||
|
|
||||||
```task
|
|
||||||
id: CB-WP-0023-T02
|
|
||||||
status: done
|
|
||||||
priority: medium
|
|
||||||
```
|
|
||||||
|
|
||||||
Update `specs/GroundRules.md` §Underdetermined for the SOLVE items, and
|
|
||||||
retire the provisional flags the ruling closes. **A ruling that lands in
|
|
||||||
code but not in the spec leaves the next reader with two sources.**
|
|
||||||
|
|
||||||
Report to `ground-game` that the ruling is implemented — closing the loop
|
|
||||||
is the part that has failed twice.
|
|
||||||
|
|
||||||
**Done 2026-08-04.** `specs/GroundRules.md` gains **GR-P05** stating the
|
|
||||||
rule and recording that the bluff reading is dead, and
|
|
||||||
`scenarios/ground/gr-p05-solve-legality.yaml` covers it — P1 refused for
|
|
||||||
holding no Clarify, P2 admitted and claiming. The prior-round-claim half
|
|
||||||
is asserted in the unit test instead, because reaching a second round
|
|
||||||
costs a dozen commands to test one rejection, and that is said in the
|
|
||||||
scenario rather than left as a gap.
|
|
||||||
|
|
||||||
## Task: evidence
|
|
||||||
|
|
||||||
```task
|
|
||||||
id: CB-WP-0023-T03
|
|
||||||
status: done
|
|
||||||
priority: high
|
|
||||||
```
|
|
||||||
|
|
||||||
`evidence/CB-EV-0020-*.md`. Short.
|
|
||||||
|
|
||||||
- **How long the inert move survived**, and what it cost: a maintainer
|
|
||||||
played SOLVE three rounds running with no effect and no explanation.
|
|
||||||
- **Whether any scenario encoded the bug.**
|
|
||||||
- **Quote CB-WP-0022's cost by re-running the instrument.**
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue