Six of seven perceptual defects fixed; item 1 already passed. T01, at the maintainer's instruction: a legal target restyles its EXISTING border rather than drawing a new box. outline + outline-offset drew a second rectangle, which an SVG viewport clips (the missing top and left edges) and which made a seat's highlight card-sized. A border already in the layout cannot move the layout. T02: the ghost was a textContent copy of the card, which is why the line break collapsed and it read as a second card, and why showing the explanation destroyed the label. It is now a pill, the explanation is appended beside the label, and the left-behind element is dimmed and dashed. The stub grew innerHTML so a test can assert BOTH are present -- it could previously only see that something was displayed. T03: NOT reproduced and recorded as not reproduced. The likeliest cause is which element the browser reports -- for touch and pen the pointer is captured to the pointerdown target, making every drop look like a drop-on-itself, which is the other half of the report. elementFromPoint is correct under both explanations. Separately the refusal was written in element ids on the one surface a player reads when something goes wrong; it now speaks the game's words and a test forbids id leakage. T04: seat selections rendered as Debug. The coverage gate then failed my first fix for dropping a field when target and problem were both set -- the aggregate does not produce that shape and the gate was right not to care. T05: the headline reads from group_success. 'Play again' is real, and its first version was useless: run_game bound a fresh listener per game, so a second game moved to a new port and left the tab pointing at a dead one. One listener per session now, and the test asserts the second game is a DIFFERENT deal. Chaos d8=8 fired the first override at the new rate and drew S, changing nothing -- one half of window 2's retirement condition. CB-WP-0019 settled at $38.54/117 against $34.80/107. Eight for eight, and the first under 20%. make all exits 0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
5e06a7d01e
commit
bf24affa84
8 changed files with 584 additions and 55 deletions
|
|
@ -130,6 +130,49 @@ pub fn describe(command: &GroundCommand, seat: cb_kernel::PlayerId) -> String {
|
|||
}
|
||||
}
|
||||
|
||||
/// Say why a drop meant nothing, in words a player can act on.
|
||||
///
|
||||
/// Deliberately does **not** consult the rules to explain *why* a move is
|
||||
/// illegal — that would be a second implementation of them. It names what
|
||||
/// was dropped on what, and leaves the reason to the log.
|
||||
fn refusal(fact: &PointerFact, seat: cb_kernel::PlayerId) -> String {
|
||||
let name = |id: &str| -> String {
|
||||
if let Some(a) = id.strip_prefix("action-") {
|
||||
let mut c = a.chars();
|
||||
return match c.next() {
|
||||
Some(f) => f.to_uppercase().collect::<String>() + c.as_str(),
|
||||
None => id.to_string(),
|
||||
};
|
||||
}
|
||||
if let Some(n) = id.strip_prefix("seat-") {
|
||||
return n
|
||||
.parse::<u8>()
|
||||
.map(|n| format!("P{}", n + 1))
|
||||
.unwrap_or_else(|_| id.to_string());
|
||||
}
|
||||
if let Some(n) = id.strip_prefix("problem-") {
|
||||
return format!("problem {n}");
|
||||
}
|
||||
match id {
|
||||
"table" => "the table".to_string(),
|
||||
_ if id.starts_with("freedom-") => "your freedom token".to_string(),
|
||||
_ => id.to_string(),
|
||||
}
|
||||
};
|
||||
if fact.down == fact.up {
|
||||
return format!("{} needs to be dropped on something", name(&fact.down));
|
||||
}
|
||||
let you = format!("P{}", seat.0 + 1);
|
||||
if fact.up == format!("seat-{}", seat.0) {
|
||||
return format!("{} cannot be aimed at {you} right now", name(&fact.down));
|
||||
}
|
||||
format!(
|
||||
"{} on {} is not a move you can make right now",
|
||||
name(&fact.down),
|
||||
name(&fact.up)
|
||||
)
|
||||
}
|
||||
|
||||
/// Resolve a pointer fact to an index into the legal list.
|
||||
///
|
||||
/// Returns `Err` rather than a default when nothing matches: a drag that
|
||||
|
|
@ -169,10 +212,12 @@ pub fn resolve(
|
|||
"{} -> {} is offered by more than one legal command; the page is ambiguous",
|
||||
fact.down, fact.up
|
||||
)),
|
||||
(None, _) => Err(format!(
|
||||
"{} -> {} is not a legal move here",
|
||||
fact.down, fact.up
|
||||
)),
|
||||
// CB-WP-0020 T03: written in the game's words, not the DOM's.
|
||||
// This read `action-attack -> action-attack is not a legal move
|
||||
// here`, which is the vocabulary of element ids — the same defect
|
||||
// the log had before CB-WP-0018, on the surface a player actually
|
||||
// reads when something goes wrong.
|
||||
(None, _) => Err(refusal(fact, seat)),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue