CB-WP-0049 T02/T03: a seat that plays its objective, and F27 splits in two
Some checks failed
ci / check (push) Has been cancelled

objective() reads GroundState::score (now public) rather than restating
what winning is; a copy in the bot would disagree with the kernel the
first time ground-game rules on F28.

Working out WHERE the modes can differ was most of the task and it
bounds the result: SOLVE always claims for the actor, so own-score and
group-score want the same SOLVE nearly everywhere. That is a fact about
GROUND's action set, not a shortcoming of the bot. Two real divergences,
both readable off the table: SUPPORT regulates someone else (worth less
against a rival, worth MORE under coalitions where a Bond merges them
into my side), and SOLVE's value is the card's value, which greedy
ignores entirely.

THE RESULT — F27 splits in two:
  group success  UNCHANGED in 34 of 36 cells
  who wins       MOVES: BONDED COALITIONS at 4p goes 2.04 -> 2.98,
                 2.12 -> 3.29, 2.05 -> 3.01 winning seats per game

So "the competitive modes are scoring lenses over cooperative play" was
too strong and is withdrawn. The sharper claim: GROUND's scoring modes
change WHO WINS, not WHETHER THE GROUP SUCCEEDS. And the effect is
seat-band dependent -- 2p none, 4p largest, 6p none under coalitions;
two relation slots capping network growth is a candidate explanation and
is untested.

The panel now prints BOTH policies side by side. That was a correction
mid-task: the first version printed only the new one and I compared it
against a figure remembered from CB-WP-0047 -- a comparison against a
board nobody re-ran.

Control that makes the numbers mean anything: under SHARED GROUND the
two policies agree at all but <=2 decision points across 12 boards, so a
moving column is mode-awareness and not simply a different bot.

Also: two T01 tests keyed on `status: proposed`, which ground-game
renamed to `ready-for-implement` mid-session. They now find the module
by asking resolve() -- the structural property is ours and does not move
when another repo edits its vocabulary.

Also: `make vendor` replaces three hand re-vendors with a tool that
regenerates digests by walking editions/, and reports one-sided files
rather than resolving them.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
tegwick 2026-08-08 23:31:11 +02:00
parent 82b9e7df31
commit 3045eb03f8
16 changed files with 859 additions and 94 deletions

View file

@ -3,14 +3,62 @@
| | |
|---|---|
| **aspect** | `end_condition` |
| **role** | End on **board clear**, **group collapse**, or **max rounds** (default max 5) |
| **status** | proposed — not yet implemented in kernel |
| **module_id** | `end_condition.hybrid_clear_collapse` |
| **role** | End on **board clear**, **group collapse**, or **max rounds** |
| **status** | **ready-for-implement** (draft frozen for v0 kernel) |
| **rules_delta** | [`rules_delta.yaml`](rules_delta.yaml) |
| **design** | [history/260808-deal-end-sequences-design.md](../../../history/260808-deal-end-sequences-design.md) |
## Draft rules (not frozen)
Independent of `problem_stress` / `problem_deal` / `attack_relief`. Measure
**alone** first, then profile `scoped_plus_hybrid_end`.
1. **Clear:** after Solve, if no unclaimed Problems remain → end game; apply mode scoring (threshold auto-success if claimed value ≥ threshold).
2. **Collapse:** if no seat has Stress ≤ 3 **or** majority of seats are in active DARVO → end as group failure (SHARED) / no personal winners (semi/coalition).
3. **Ceiling:** if Round Max (5) completes without (1) or (2) → current threshold scoring.
## Frozen v0 rules
**Compose with** any problem_stress / deal / attack_relief.
**Kernel:** not shipped — package `rules_delta.yaml` when implemented.
### END-CLEAR
After the **Solve** step: if **zero** unclaimed Problems remain in play →
**end the game immediately**.
- Apply mode scoring as usual.
- **Threshold:** if total claimed value ≥ scenario threshold for seat band →
group success (SHARED mastery / semi-coalition personal winners as normal).
- If claimed value &lt; threshold but board is empty (should be rare) → group
**failure** (nothing left to claim).
### END-COLLAPSE
After Round End stress clamp (and problem-stress ticks if any module active),
before Lead rotation:
**Collapse** if **either**:
1. **No seat has Stress ≤ 3**, or
2. **Majority** of seats are in an **active DARVO sequence** (stage ≠ OFF).
Effect:
- End the game.
- **Group success = false** (SHARED fails).
- Semi / coalition: **no personal / coalition winners** (table broke).
### END-CEILING
If Round **5** completes without CLEAR or COLLAPSE → end with current
threshold + mode scoring (identical to baseline fixed-rounds behaviour).
Round max is **5** in v0 (same product length as r0). Changing max is a
different module later if needed.
## Non-goals (v0)
- Soft collapse (one seat at 5 only).
- Extending rounds when board not clear.
- Mode-specific collapse exceptions.
## Success criteria (when clay-borg implements)
1. Alone on baseline content: some games end before round 5 (clear or collapse).
2. Mean game length ≤ 5 rounds; no hangs.
3. With `problem_stress.scoped`: collapse rate non-zero for unregulated policies;
clear rate non-zero for greedy SHARED at 34p.
4. Does not recreate H1-style 0% greedy wins solely via collapse spam.

View file

@ -1,10 +1,11 @@
# module: end_condition.hybrid_clear_collapse — PROPOSED
# module: end_condition.hybrid_clear_collapse
# status: ready-for-implement (v0 rules frozen in MODULE.md)
module_id: end_condition.hybrid_clear_collapse
aspect: end_condition
schema_version: 1
base: ground-darvo-r0
status: proposed
implementation: pending
status: ready-for-implement
implementation: pending_kernel
deltas:
- id: END-CLEAR
@ -15,7 +16,8 @@ deltas:
effect:
end_game: true
scoring: mode_as_usual
note: threshold treated as met if claimed_value >= threshold
group_success_if_claimed_ge_threshold: true
group_fail_if_claimed_lt_threshold: true
- id: END-COLLAPSE
name: early_end_group_collapse
@ -30,7 +32,7 @@ deltas:
personal_winners: none
- id: END-CEILING
name: max_rounds_unchanged
name: max_rounds_five
phase: after_round
when:
round_completed: 5

View file

@ -3,14 +3,75 @@
| | |
|---|---|
| **aspect** | `problem_deal` |
| **role** | Start with a small set; draw additional scoped Problems mid-game from a Pressure deck |
| **status** | proposed — not yet implemented |
| **module_id** | `problem_deal.pressure_deck` |
| **role** | Small start set + mid-game **Pressure deck** draws |
| **status** | **ready-for-implement** (draft frozen for v0 kernel) |
| **rules_delta** | [`rules_delta.yaml`](rules_delta.yaml) |
| **design** | [history/260808-deal-end-sequences-design.md](../../../history/260808-deal-end-sequences-design.md) |
## Draft rules (not frozen)
Independent of end_condition. **Recommended** compose with
`problem_stress.scoped` so drawn scopes matter. Measure alone first if
possible (with default problem_stress.none, influx still adds board clutter).
1. **Setup:** Surface (global) + 12 starters (mostly personal). Remaining scenario Problems form face-down **Pressure deck** (shuffled).
2. **Influx:** at Round End, if unclaimed count &lt; open_cap (e.g. seats) and deck non-empty, draw 1 into play face-down (or face-up if global).
3. **Owner:** personal → next clockwise from Lead among seats / drawer rule TBD; bond → owners network; global → none.
4. **Scoring (v0):** drawn cards may be **stress-only (0 points)** so thresholds stay on starters — decide before kernel work.
## Frozen v0 rules
**Compose with** `problem_stress.scoped` (recommended) so drawn scopes matter.
### DEAL-START
- **Always in play at setup:** Surface Problem (priority 0).
- **Also deal face-down:** hidden priority **1** (and priority **2** only if
seats ≥ 4).
- All other scenario Problems for that scenario go into the **Pressure deck**,
shuffled with the game seed (deterministic).
- Seat-band `k` from r0 does **not** bulk-deal the rest; influx replaces
“deal all k at once.”
| seats | starters in play | rest → pressure deck |
|------:|------------------|----------------------|
| 23 | Surface + H1 | H2… |
| 46 | Surface + H1 + H2 | H3… |
### DEAL-INFLUX
At **Round End** (after problem-stress ticks if any, before DARVO arm):
- If Pressure deck non-empty **and** unclaimed Problems in play &lt; **open_cap**,
draw **1** card into play.
- **open_cap** = number of seats.
- Placement: face-down if hidden/personal/bond as printed; Surface-like global
face-up if scope is global.
- Stop drawing for that End once one card is drawn (v0: max 1 per round).
### DEAL-OWN (if problem_stress.scoped also active)
- **personal:** owner = Lead at time of draw (or next free seat clockwise if
Lead already owns ≥2 personal — v0 simplify: **drawer seat = current Lead**).
- **bond:** same owner rule; network = Bond network of owner.
- **global:** no owner.
If `problem_stress.none`, owners may still be recorded for table clarity but
have no stress effect.
### DEAL-POINTS (v0)
- Cards that entered via **Pressure deck draw** have **point_value 0** for
scoring (stress / fiction only).
- **Starters** keep printed `point_value`.
- Scenario **thresholds unchanged** (5/7/9) and apply only to starter claims
+ any printed values that were starters.
This avoids reopening GR-E01 arithmetic while testing influx.
## Non-goals (v0)
- Problems in Solution hand.
- Multiple draws per round.
- Owner-only SOLVE.
- Changing thresholds mid-game.
## Success criteria (when clay-borg implements)
1. Games show mid-game influx (deck depletes or open_cap binds).
2. With scoped stress: variance and DARVO still possible; greedy SHARED 34p
wins not collapsed to H1-zero.
3. Threshold success still well-defined (starter points only).
4. Composable: works with default end_condition and with hybrid end.

View file

@ -1,18 +1,19 @@
# module: problem_deal.pressure_deck — PROPOSED
# module: problem_deal.pressure_deck
# status: ready-for-implement (v0 rules frozen in MODULE.md)
module_id: problem_deal.pressure_deck
aspect: problem_deal
schema_version: 1
base: ground-darvo-r0
status: proposed
implementation: pending
status: ready-for-implement
implementation: pending_kernel
deltas:
- id: DEAL-START
name: reduced_initial_deal
phase: setup
effect:
initial_in_play: [surface, hidden_priority_1]
# optional: also priority_2 at 4p+
seats_2_3_initial: [surface, hidden_priority_1]
seats_4_6_initial: [surface, hidden_priority_1, hidden_priority_2]
remainder_to: pressure_deck
pressure_deck_shuffle: deterministic_seeded
@ -21,14 +22,24 @@ deltas:
phase: round_end
when:
pressure_deck_nonempty: true
unclaimed_count_lt: open_cap # open_cap := seats (proposed)
unclaimed_count_lt: open_cap
effect:
open_cap: seat_count
draw_problems: 1
place: in_play_face_down_unless_global
max_draws_per_end: 1
place: face_down_unless_global_scope
- id: DEAL-OWN
name: owner_on_draw
phase: on_pressure_draw
effect:
personal_or_bond_owner: current_lead
global_owner: none
- id: DEAL-POINTS
name: drawn_card_scoring
phase: data
effect:
drawn_point_value: 0 # v0: stress-only; revisit
starter_threshold_unchanged: true
drawn_point_value: 0
starter_printed_values: unchanged
thresholds: unchanged_5_7_9