CB-WP-0028 T03/T08: one overhead table, and what the nine observations
Some checks failed
ci / check (push) Has been cancelled

turned out to be

T03. One table_svg: seats around an elliptical table starting at the
BOTTOM -- the viewer sits nearest the reader, as at a real table --
Problems and both stacks in the middle, each seat's played card between it
and the centre, relations drawn between seats.

Two renderers were DELETED: relations_svg and piles_svg. The task said one
table not two diagrams, and leaving the old ones would have meant drawing
the same thing twice and letting them drift.

No coverage probe cost, through a restructure that merged three diagrams
and removed two functions. Second confirmation of CB-WP-0027's finding: a
probe naming a FACT survives a reflow, one naming a PRESENTATION does not.
CB-WP-0024's "17 remaining" broke on a rendering change; this far larger
reflow broke nothing.

The new control is per seat count -- no two seat circles closer than 70px
at 2 through 6 -- asserted rather than eyeballed at three, which is the
only count anyone ever looks at.

T08 (CB-EV-0026). Seven of nine observations were engine defects, one was
a design finding, one was already true and nobody could tell.

Observations 4 and 5 both dissolved and had ONE cause: nothing on the page
said how drawing works, so a player built a mental model to fill the gap
and reported the gap as two feature requests.

The import gap was worse than "one of nineteen" -- 5 of 13 columns read
from the file we DID vendor, discarded at parse time for eight days. Rule
coverage was 59/59 throughout. The gate measures whether rules are
EXERCISED; nothing measures whether a player can READ the game, and
nothing cheaply could, which is why the person playing it is the
instrument.

TWO GATES WERE WRITTEN FOR A SMALLER WORLD, and neither was wrong when
written. edition-check compared one recorded digest against Problems.csv
regardless of which file it described -- correct with one vendored file,
comparing across files with four. And a cb-play test asserted the literal
"game over" and went red when a won game said "solved", which was T06
working; it now asserts the heading against the OUTCOME and covers the
no-outcome case the original never touched.

Chaos window 2 closes with zero overrides in eleven declarations at d8.
Third and final statement of it: d8 bought rarity by spending evidence,
and a mechanism producing no data across a full window cannot be evaluated
by that window.

make all: exit 0. 57 render tests, 26 cb-play, loop-lint clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
tegwick 2026-08-06 17:33:57 +02:00
parent 4d3e30eda4
commit eb8aa64c56
5 changed files with 459 additions and 122 deletions

View file

@ -714,6 +714,119 @@ mod piles {
}
}
/// CB-WP-0028 T03 — one overhead table, not three diagrams.
#[cfg(test)]
mod overhead_table {
use cb_game_runtime::{Project, ScenarioGame, Setup, Viewer};
use cb_kernel::PlayerId;
use games_ground::GroundState;
fn view_of(players: u8) -> games_ground::view::GroundView {
GroundState::setup(
&Setup {
players,
preset: format!("standard-{players}p"),
patch: Default::default(),
},
7,
)
.expect("preset")
.project(Viewer::Player(PlayerId(0)))
}
/// **Every seat count lays out, and no two seats land on each other.**
/// Asserted per count rather than eyeballed at three, which is the
/// only count anyone ever looks at.
#[test]
fn two_through_six_seats_all_lay_out_without_overlap() {
for players in 2..=6u8 {
let v = view_of(players);
let html = crate::doc::document(&v, &[], "/command?t=x", Some(PlayerId(0)), false);
let seats: Vec<(f64, f64)> = html
.match_indices("<circle cx=\"")
.filter_map(|(i, _)| {
let rest = &html[i + 12..];
let (x, rest) = rest.split_once("\" cy=\"")?;
let (y, _) = rest.split_once('"')?;
Some((x.parse().ok()?, y.parse().ok()?))
})
.collect();
assert_eq!(
seats.len(),
players as usize,
"{players}p: expected one circle per seat, got {seats:?}"
);
for (i, a) in seats.iter().enumerate() {
for b in &seats[i + 1..] {
let d = ((a.0 - b.0).powi(2) + (a.1 - b.1).powi(2)).sqrt();
assert!(
d > 70.0,
"{players}p: two seats are {d:.0}px apart and the circles are r=34 — \
they overlap"
);
}
}
}
}
/// A table where you cannot find yourself is worse than a list.
#[test]
fn the_viewers_own_seat_is_marked() {
let v = view_of(4);
let html = crate::doc::document(&v, &[], "/command?t=x", Some(PlayerId(0)), false);
assert!(
crate::text_of(&html).contains("P1 (you)"),
"the viewer's seat is not identifiable"
);
assert!(
html.contains("stroke=\"#9cf\" stroke-width=\"3\""),
"the viewer's seat should also be visually distinct, not only labelled"
);
// A spectator has no seat to mark, and must not claim one.
let spec = GroundState::setup(
&Setup {
players: 4,
preset: "standard-4p".into(),
patch: Default::default(),
},
7,
)
.expect("preset")
.project(Viewer::Spectator);
assert!(
!crate::text_of(&crate::doc::document(&spec, &[], "/x", None, false)).contains("(you)"),
"a spectator was given a seat"
);
}
/// The three diagrams became one: the relationship circle and the
/// piles picture are gone as separate views, and their content is on
/// the table.
#[test]
fn the_stacks_and_the_relations_are_on_the_table() {
let v = view_of(3);
let html = crate::doc::document(&v, &[], "/command?t=x", Some(PlayerId(0)), false);
let table = html
.split("aria-label=\"the table, seen from above\"")
.nth(1)
.and_then(|s| s.split("</svg>").next())
.expect("one table svg");
assert!(
table.contains("draw pile:"),
"the draw stack is not on the table"
);
assert!(
table.contains("discard pile:"),
"the discard is not on the table"
);
assert!(
!html.contains("relationship graph"),
"the old separate relationship diagram is still being drawn"
);
}
}
/// CB-WP-0028 T02 — the cards say what they do, in the edition's words.
#[cfg(test)]
mod card_words {
@ -936,7 +1049,7 @@ mod two_columns {
.and_then(|s| s.split("class=\"cb-meta\"").next())
.expect("a game column followed by a meta column");
assert!(
game.contains("<h2>problems</h2>"),
game.contains("<h2>the table</h2>"),
"the table must be in the game column"
);
assert!(