diff --git a/workplans/CB-WP-0023-solve-legality.md b/workplans/CB-WP-0023-solve-legality.md new file mode 100644 index 0000000..b24edb5 --- /dev/null +++ b/workplans/CB-WP-0023-solve-legality.md @@ -0,0 +1,97 @@ +--- +id: CB-WP-0023 +kind: product +title: "SOLVE is offered only where it can do something" +status: active +--- + +# 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: todo +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. + +## Task: retire what the ruling settles + +```task +id: CB-WP-0023-T02 +status: todo +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. + +## Task: evidence + +```task +id: CB-WP-0023-T03 +status: todo +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.**