Declaration 12 of chaos window 2, which CLOSES IT. Structural M (imports
another edition file under AM-4's budgets), chaos d8=4, no override.
Tokens.csv turns out to carry more than names. Every token has a
`quantity` -- 6 Protection, 5 Denied, 12 relation links -- and a component
count is a limit a simulation does not have unless it is told. protection
is saturating_add(1) at lib.rs:986 with no upper bound, against an edition
that ships six tokens for six players. T03 measures whether that matters
rather than assuming either way.
And `sides` is the second interesting column: Freedom and Focus/Blame are
each ONE DOUBLE-SIDED TOKEN, not two states. The engine holds Focus in a
map and Blame in a list; whether those can disagree with a single physical
token is worth checking.
T03 is shaped against a specific error: whatever it finds is a FINDING,
not a fix. A component limit the rules do not state is underdetermined and
belongs to ground-game, and the engine must not start enforcing a bound
nobody ruled. CB-WP-0023 exists because SOLVE was offered where it could
not act; inventing a limit is the same error in the other direction.
The workplan also names the window-2 verdict as DUE. Its retirement
condition was untestable throughout -- eleven declarations, zero 8s, zero
overrides -- and recording that is a change to how the loop constrains
itself, so it is its own tier-M pass rather than a task here. Named so it
is not lost between passes, which is how the ten rulings went uncollected.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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>
a feature deliberately not built
T04 BUILT NOTHING, WHICH IS THE CORRECT OUTCOME. "Click the draw stack to
get hand cards" is not a legal move: GroundCommand has no standalone draw,
and the edition's own INVESTIGATE text settles it -- "Choose one hidden,
non-Denied Problem and reveal it. THEN DRAW ONE SOLUTION." Drawing is a
consequence, never an action. Implementing click-to-draw would have
invented a rule, which is what CB-WP-0023 exists to stop.
And observation 5 is already true: drawing is ALREADY automatic, inside
INVESTIGATE, with no player input. An auto-draw option was asked for a
thing that has never been manual.
Both observations have one root cause and T02 fixed it. The maintainer
expected to take cards from the deck because NOTHING ON THE PAGE SAID HOW
DRAWING WORKS -- the INVESTIGATE card's own text was in a file we had not
imported. No finding raised: a player's instinct differing from a legible
rule is a comprehension gap, not a rules gap. Whether the instinct recurs
now that the text is present is a testable question and was not before.
T06: "game solved" on a win, "game over" on a loss, "the game stopped"
with no outcome. Asserted all three ways, because a test checking only the
win case passes for a page that always says solved. More than tone --
GROUND is co-operative and about repairing something, and arcade
failure-state vocabulary for a win tells a player the wrong thing about
what they just did.
T05: the ending page gets the table's two-column shape. Result left;
rankings, controls and the full log right. The seal still removes every
control wherever they now live.
T07's interesting decision was NOT TO RANK. Modes.csv defines
scoring_tiebreak per mode, so ordering is the GAME's where one exists --
"Lower combined Stress, then fewer Blame tokens" for coalitions. For
SHARED GROUND it says "Not applicable", because the table succeeds or
fails together. So co-op shows contributions and refuses to order them,
and says why. Drawing a leaderboard because a leaderboard is easy would
invent scoring the rules do not have. The one derived superlative is
labelled "clay-borg's reading, not a rule" and appears only where the mode
ranks; ties are shown as ties.
52 render tests pass. check clean, loop-lint clean.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
ADR-0015 and the import. F18's fix: "I don't understand the GROUND card"
was never a design gap -- the card explains itself in the edition and we
never imported the explanation.
THE MEASUREMENT IS THE DECISION, and the gap is bigger than "one file of
nineteen". Of the file we DID vendor, the engine reads 5 of 13 columns:
title, problem_text, front_rules, reveal_effect and unresolved_effect were
discarded at parse time. The cheapest part of this pass costs no new bytes
and was sitting in the repo for eight days. And SCN_01 is hardcoded at
lib.rs:1824 -- the edition ships FOUR scenarios and the engine has never
dealt three of them. Nobody had said so.
ADR-0011's revisit condition is measurably absent, so the dependency
argument does not get re-run: across Actions, Solutions, Modes and
Scenarios there are ZERO doubled quotes and ZERO embedded newlines. The
hand reader's only job is comma-in-quoted-field, which it already did.
Refusing csv on a measurement rather than on a preference.
Vendored Actions, Solutions and Modes -- the text a player reads. Not the
production artifacts (BOM, Print_Manifest, Back_Designs, Symbols). NOT
Extensions.csv, which names content the designer placed outside the core;
importing it would break the claim that this engine plays the edition as
printed. It is now known to exist, which was the real risk.
One Table reader with four callers, because a per-file copy is how a
parser acquires four subtly different bugs. The GROUND card now shows
"Regulate. Restore the frame. Decide." with its GR/OU/ND text on demand;
Problems show their own titles where a priority number used to be.
The load-bearing test asserts the text is a SUBSTRING OF THE VENDORED
FILE rather than equal to a Rust literal -- a test comparing against a
hardcoded expectation would pass for a hand-copied string, which is the
drift this ends.
`edition` came out from behind #[cfg(feature = "scenarios")]. It was gated
because its only consumer was; the edition is the game's own data and the
shipped runtime now reads it. Test machinery and game content are
different things and only one of them is optional.
And edition-check was written for a single-file world: it compared the
first recorded digest against Problems.csv regardless of which file that
digest described. It now checks every file both ways -- a vendored file
with no digest fails, a digest naming an absent file fails -- and asserts
ADR-0015 D3's falsifier directly rather than trusting it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Nine observations from the maintainer's session. Two are about the game
and go to the register; seven are about the engine and are this workplan.
F18 IS THE ONE THAT REFRAMES THE PASS. "I don't understand the GROUND
card" reads as a design problem. It is not: Actions.csv carries that
card's own tagline -- "Regulate. Restore the frame. Decide." -- and its
full rules text, and clay-borg never imported it. We vendored ONE OF
NINETEEN edition files. Everything else the engine knows is a
hand-transcription into GroundRules.md's 59 numbered rules, which is
enough to PLAY the game and gives a player nothing to READ. The page shows
`Clarify` where the card says "Ask What Happened -- Invite a concrete
account before judging." Registered as `inert`: the data exists and cannot
fire, because nothing reads it.
Found by a player saying he did not understand something. Rule coverage is
59/59 and has been for weeks.
F17: no incentive to ATTACK while holding useful Solutions. Registered as
a NOTE, not a finding -- no artifact demonstrates it, and under GameDesign
§3.1 it may not go to ground-game until one exists. One is cheap (count
ATTACK selections across the policy panel against hand quality). Owner is
ground-game if it survives, since it would be a design finding.
The workplan (M, chaos d8=1, no override, declaration 11 of window 2)
carries the seven engine observations. Two tasks are deliberately shaped
against past mistakes:
T01 must decide whether ADR-0011's hand-rolled CSV reader survives
Solutions.csv, whose microcopy and rules_text are prose with commas and
quotes -- ADR-0011 named exactly that as its revisit condition, so if the
reader cannot parse them the dependency argument gets re-run rather than a
fragile parser written.
T04 must first establish whether "click the deck to draw" is a legal move
at all. GR-A01 draws as part of INVESTIGATE; the deck is not a thing a
player may take from. If it is not legal, that is a FINDING for
ground-game -- the maintainer expected an interaction the rules do not
offer -- and not a feature. CB-WP-0023 exists because SOLVE was offered
where it could not act.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
CB-EV-0025. T05 asks whether a comment actually got written during play,
unprompted. It has not been, and that is the pass's real acceptance test.
Everything built here is evidence the mechanism works; none of it is
evidence it gets used. I exercised it myself, which proves the plumbing
and proves nothing about the ergonomics -- the person who wrote the
feature is the worst possible witness to whether it is worth using.
Stated plainly rather than answered optimistically, because CB-WP-0022
built a register whose first run found ten answers nobody had collected:
this project's failures are about whether things get READ.
ADR-0007 D5 turned out to be the easy part. PointerFact::parse already
refuses any unrecognised field, so a comment could not reach the command
path even by accident. That is strictness at a boundary paying off years
early, and the clearest instance in this project of it being cheaper than
vigilance across one.
esc() held against its first hostile input, and the test asserts the
harder half: the player's words are still READABLE after escaping. An
escaper that dropped the text would pass "no script tag in the output"
while destroying the note.
The reflow cost no coverage probe -- all 41 pre-existing render tests
passed through a full restructure into two columns. CB-WP-0024 saw the
opposite when a probe was tied to a rendering ("17 remaining"), and the
contrast is the useful part: a probe that names a FACT survives a reflow,
a probe that names a PRESENTATION does not.
Running it changed the design for the third pass running, after
CB-WP-0024's role column and CB-WP-0025's K=2 infeasibility. The pattern
is consistent enough to state: the ADRs in this project are good at
deciding and poor at predicting, and the loop's value comes
disproportionately from the code loop rather than from steps 1-3.
Chaos window 2 closes with zero overrides in twelve declarations, so its
retirement condition is untestable -- final now rather than projected. The
window's verdict should be that d8 made the mechanism unevaluable.
Also recorded rather than dismissed: make all failed once at env-test and
passed on re-run. A cb-play server and several cargo processes were
running concurrently, which is the likely cause -- but "likely" is doing
work in that sentence and I did not chase it. A gate that fails
intermittently and is re-run until green is a gate being trained not to
matter.
Not built, and named: promoting a comment to a register note is still
manual.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The meta view beside the table, and a note channel that provably cannot
carry a move.
T01 (ADR-0014). ADR-0007 D5 is SCOPED, NOT AMENDED, and the reason it was
easy is that PointerFact::parse already refuses any unrecognised field --
a comment could not reach the command path even by accident. So /command
carries pointer facts, /note carries text, and Note has no code path to
GroundCommand. Comments live in trials/<date>-<slug>.md, not in
ScenarioFile: a scenario is executed, replayed and hashed, and prose in it
is data the runner must ignore, which is how a format rots. The state hash
binds; round and step are for reading. And the retention question, decided
before any comment was written: RAW NOTES NEVER LEAVE clay-borg. A note
reaches ground-game only by being promoted to a register finding, by a
human, with the wording chosen then -- "the DARVO sequence is infuriating"
is useful signal and a bad way to open a message to the game's designer.
T02. CSS grid, minmax(0,1fr) on both tracks -- load-bearing, because a
grid child defaults to min-content width and without it the SVG table
refuses to shrink and pushes the meta column off-screen, looking correct
on the developer's monitor and broken everywhere else. Single-column
fallback under 64rem. The running tally moved into the panel so it is
visible WHILE PLAYING; it only appeared on the ending page before, and a
score you see once the game is over informs nothing.
T03. A plain <form method="post">, so the box works with the script
disabled; the command channel needs JavaScript because a drag is not a
form submission, a comment is one. 303 See Other so a reload does not
re-post. esc()'s first hostile input: <script>alert(1)</script> renders
escaped AND STILL READABLE -- escaping that eats the player's words is its
own defect. Verified over real HTTP: note posted 303, hostile note stored
as text, empty note refused 400, game did not advance.
T04. tools/trials.py and make trials. THE REPORT'S DESIGN CHANGED BECAUSE
I RAN IT: the first version called any note without a recording an orphan,
so a live session reported every note as broken -- the recording is only
written at game end. A metric that cries wolf is one nobody reads, which
is the exact failure this pass exists to prevent. Now ok / pending /
orphan, and only orphan is a target-0 number. The self-test exercises the
REPORTING path, not just the parser, because design-baseline.py had a
green self-test and an unexercised reporting path and that is where it
rotted.
And a latent Makefile defect surfaced: make trials did nothing, because
trials is also a directory and Make saw an up-to-date file. design,
difficulty and trials -- added by CB-WP-0022, CB-WP-0025 and this pass --
were ALL missing from .PHONY; only the one that collided revealed it.
make all: exit 0. 49 render tests, 26 cb-play, loop-lint clean.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The maintainer's ask: game interface left, meta and commentary right, with
comments bound to game state so a test player's perception, confusion and
reasoning become reviewable signal.
Declared M (chaos d8=7, no override, declaration 10 of window 2). It
touches two canonical interfaces: ADR-0007 D5's input contract, which
currently admits only raw pointer facts, and the recorded-session format,
which is deny_unknown_fields -- CB-WP-0026 just proved that bites.
FRAMED AS GameDesign §5's TRIAL PROTOCOL MADE ERGONOMIC, because that is
what it is. The protocol already exists and nobody would use it as
written: it asks the player to reconstruct their reasoning afterwards,
from memory, in a sibling file. A comment typed while the position is on
screen is contemporaneous, bound to something replayable, and captures the
one class of signal no gate in this project can see -- confusion and
frustration.
The reason it is worth more than a comment box: GameDesign §3.1 makes a
note unreportable until it has a reproduction, and three findings are
stuck there now (F12, F14, F15). A comment bound to a recorded state, plus
the recording, is the cheapest reproduction a play-derived observation can
have. So the pass closes the register's input path for findings that come
from playing rather than from building.
The failure it must not reproduce is named up front: a pile of prose
nobody reads is this project's signature defect -- the four-day unread
message, the ten uncollected rulings. Storage is not the deliverable,
surfacing is, and T04 carries it.
T01 (ADR-0014) must decide where comments live, what the page may send
(D5's transport widens from two ids to arbitrary user text -- amended or
merely scoped?), what binds a comment to a position, and the retention
question this project has not faced: these are the maintainer's own words
about his own game, one will eventually be unflattering, and whether they
travel to ground-game needs deciding before any are written.
T03 notes that esc() is about to face its first hostile input -- until now
it has escaped suit names.
loop-lint: no findings.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
T06. games/ground/examples/difficulty.rs, make difficulty, wired into make
self-tests, and a report file in ground-game under GROUND-WP-0005 with a
hub message pointing at it.
THE REPORT OPENS WITH THE RETRACTION, because what this task was written
to send was withdrawn by T02 and GROUND-WP-0005 is blocked on exactly that
number. They are told, in the first section, that we nearly sent them "the
game is too easy at 5-6 seats" and why it was wrong.
seats winnable greedy random first-legal spread
2p 60% 60.0% 5.0% 76.7% 71.7
3p 93% 88.3% 6.7% 25.0% 81.7
4p 100% 93.3% 6.7% 30.0% 86.7
5p 100% 100.0% 3.3% 0.0% 100.0
6p 100% 100.0% 3.3% 0.0% 100.0
SPREAD justifies the whole redesign: 71.7 to 100.0 points between three
trivial policies. The table now shows why no single rate is a difficulty
rather than asserting it.
And the 5-6 rows point the OPPOSITE way from the withdrawn claim --
first-legal 0% against greedy 100% is the widest spread in the table,
which suggests play matters MORE there, not less. Neither reading is
established and the report says so.
The confound is stated in the tool's own output, not only in prose:
`winnable` is conditioned on greedy's play up to the final round, because
searching from round 1 is unaffordable. Presenting it as a property of the
deal would repeat this pass's error in a subtler form -- which is exactly
how a corrected project reintroduces a defect. NO THRESHOLD CHANGES ARE
PROPOSED.
The instrument can fail (spec §5): a witness must replay to a win, an
unwinnable position must report searched-out rather than a budget cut, a
one-node budget must not claim exhaustion, and the policy panel must
actually disagree. difficulty-baseline.rs marked superseded, kept as the
survey's dated snapshot. Registered as F16, inconsistent / withdrawn.
T07. evidence/CB-EV-0024. Five of nine defects came only from the review;
four from execution, and all four of those were in work written after it.
The wrong-denominator family now has five instances and still no control
-- facts-check catches copies that disagree, nothing catches a number
computed correctly against the wrong base. Tier L was an over-declaration
(no port, structurally M) and paid for itself anyway, because the review
is L-only. Chaos window 2 will close with zero overrides, making its
retirement condition untestable.
Named as open rather than implied done: the witness is NOT wired to the
ending page. The search works; the browser cannot ask it yet.
make all: exit 0. loop-lint clean.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
affordability projection
games/ground/src/search.rs, five tests. It finds real winning lines and
replays them through validate/fold to group_success.
Two bugs in my own work, found and fixed here.
THE TRAVERSAL WAS WRONG. It branched on "the first seat with any legal
command" and stopped there, so a later seat never acted if an earlier one
was already selected but still had a legal move. Restructured around what
the rules oblige: a seat without a selection MUST select (GR-R02) and
nothing else can happen first; after Reveal the optional actions branch
freely and the aggregate rejects Resolve until the obligatory ones are
done -- so the search needs no phase logic of its own.
AND MY REWIND WAS OFF BY ONE ROUND, replaying the round it was meant to
search. That is why the first run reported 3 nodes and looked like a
working search.
Measured with the real search, rewinding real games to the start of their
last K rounds:
2p K=1 exhausted, 8,103 nodes, ~29 ms
2p K=2 budget cut at 2,000,000 nodes, ~5 s
3p K=2 win found, 41 nodes, ~157 us
The spec's own falsifier said "§3 fails if K=2 proves unaffordable at four
seats". IT FAILED AT TWO. The projection assumed a joint product per
round; the search explores sequential per-seat decisions, so orderings
multiply the tree far beyond width^seats. That is the second projection
this pass published in place of a measurement -- C1's timer was the first.
THE ASYMMETRY IS THE OPERATIVE FINDING. Finding a win is cheap: DFS
stumbles onto one in tens of nodes. Proving none exists needs exhaustion.
So the witness feature is affordable now at any K a player would ask
about, and the winnable fraction (ADR-0013 D4) is NOT, because its
negative half must exhaust every deal it counts. K=1 is the honest default
for exhaustive answers today; making K=2 exhaustible needs transposition
or move-ordering, neither of which this pass built. specs §3 and §3.1
corrected accordingly, and the K=2 default withdrawn.
The negative control that makes "winnable" falsifiable: 2p seed 7 over its
last round returns NoneFound with exhausted=true in ~8k nodes -- a real
negative, not a budget cut wearing a verdict's clothes. And the visible/
hidden marking is tested both ways, since a marking that can only say YES
is decoration.
make all: exit 0. loop-lint clean.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
caught me repeating C1
specs/RetrospectiveAnalysis.md v1.0 plus games/ground/benches/search.rs,
which exists because ADR-0013 D7 refused to let the spec quote either
disputed figure.
THE BENCHMARK'S OWN FIRST FIXTURE WAS DEFECTIVE, and it is the same defect
class the review caught one layer up. Stopping at a fixed step 20 put 2p
and 4p in states where seat 0 had NO legal commands, so it timed an empty
Vec (~120 ns) and silently skipped validate_fold because there was nothing
to validate. It now advances until the seat has a real branch and ASSERTS
it. A clone benchmark was added too: a search must copy state per branch,
and iter_batched excludes setup from timing, so without it the budget
would again rest on an unmeasured span.
Measured at real decision points: legal_commands 4.06-4.76 us, clone
378-639 ns, validate+fold 0.5-3.8 us. Per-child cost is NOT uniform --
some commands resolve cascades -- so budgets use the upper end (~5
us/child).
That settles D3 with real numbers. Joint branching over the last two
rounds is ~5x10^2 / 1.6x10^5 / 5.7x10^5 at 2/3/4 seats, so K=2 costs
negligible / 0.8 s / 2.9 s and holds at two to four seats. It does NOT
hold at five or six, where the tool must reduce K and say that it did
rather than silently searching less.
§4.1 is a normative prohibition, not a preference: a single policy's win
rate MAY NOT be reported as a difficulty. The spec carries the measured
reason -- greedy 100% against first-legal 0% on identical deals -- because
this project already made that error and nearly exported it to a repo that
is blocked waiting on the number.
§2.3 makes the empty-result wording normative: "no winning line found in
the last K rounds", never "unwinnable". A bounded search cannot establish
unwinnability and that sentence is what a player who just lost reads.
Also corrected: the T01 completion record still asserted all three
withdrawn claims as fact. It now carries claimed / withdrawn / survives
explicitly rather than being rewritten -- a retraction that does not
propagate to every place the claim lives is how the earlier ones survived.
make all: exit 0. loop-lint clean.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
does not measure the bot
Seven decisions. Two are not what T03 expected, because the review moved
the ground under both.
D1: strategy fusion DOES NOT APPLY, and that is why the affordable option
is also the honest one. Fusion is a defect of aggregating over
determinizations to choose a move -- the search picking different actions
in states a player cannot distinguish. After the game there is ONE WORLD:
the deal is known, so a search over it yields a line executable in the
only world there is. The survey treated fusion as this pass's central
obstacle; it is an obstacle to a playing engine, which we are not
building. The tool answers "given the deal as it actually was, was there a
line that reached the threshold" and is labelled that way on screen --
never "how you should have played".
D4: difficulty is the WINNABLE FRACTION, not a bot's win rate. C4 killed
the bot rate -- two trivial policies span 0-100% on the same deals, and
improving the bot would make the game "easier" without a rule changing. A
measure that moves when the measurer improves is not measuring the thing.
The solver supplies the alternative: over N deals, in what proportion does
a winning line exist. That is a property of the deal distribution and the
threshold, which is what ground-game tunes and what GROUND-WP-0005 is
blocked on. Ships as a table -- winnable fraction, named reference policy,
skill gap -- never one number, with policy/N/seed-range/K in the number's
name. Stated as a LOWER BOUND, since a K-round search cannot see a line
that needed round 1.
D2: search GroundState. The survey's view-only structural boundary is not
implementable -- a view cannot fold events, and it said so in §6. The
guarantee moves to something checkable: every move in a witness is marked
visible or hidden, computed from project(). A witness reads "you could
have won, but two of these six moves needed a card you had no way to know
was coming" -- more useful than either extreme.
D3: bounded exhaustive over the last K rounds, table as one co-operative
agent, K=2 default. Affordable once C6 corrected the premise: joint
branching over the last two rounds is ~5x10^2 / 1.6x10^5 / 5.7x10^5 at
2/3/4 seats. Wording is normative: "no winning line found in the last K
rounds", never "unwinnable". PIMC and ISMCTS rejected -- they add strategy
fusion to a problem that does not have it.
D5: the harness becomes an instrument before any figure is quoted (C3) --
positive controls, --self-test in make self-tests, a make target, and a
PLURAL policy panel, because the spread between policies is what C4
exposed and hiding it would restore the error.
D6: no new crate and no port. The L declaration was an over-declaration
and is recorded as one. D7: the node cost is disputed 5x between author
and reviewer; T04 benchmarks it with criterion and neither existing figure
may be cited, including by this ADR.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
premise never left the repo
Separate agent, second tier-L review in this project. Six of seven
challenges conceded. The survey's headline finding is WITHDRAWN, not
softened.
C4 kills it, and the reviewer ranked it fourth. A FirstLegal policy --
take legal[0], no heuristic at all -- scores 0% at five and six seats
where GreedyPolicy scores 100%, and 77.5% at two seats where greedy scores
66%. Two unsophisticated agents span the entire range at the same seat
count. "The game is too easy at 5-6 seats" is therefore a statement about
GreedyPolicy, not about GROUND. The rescue the reviewer offered -- greedy
hits the 12-point ceiling in 200/200 deals, so the 6p row is a rules claim
-- dies on the same data: FirstLegal reaches that ceiling never.
C1: the per-node cost was wrong by 30-50x. The timer started before the
seed loop, so "us/node" included two setups, an entire greedy game and a
full validate+fold replay, divided by player-decision count. The tell was
in my own published output and I did not look at it: the figure FELL
(161/139/112) as branching ROSE (4.7/7.4/9.1), which no per-enumeration
cost can do. Re-measured with the clock around legal_commands alone:
3.0/3.5/4.1 us, now rising with branching. The reviewer measured 15.6-20.4
by a different isolation; we disagree by ~5x and neither has established
which is right, so T04 must benchmark it with criterion rather than adopt
either number.
C6: "exhaustive search is out at any seat count" is false -- ~3 seconds
over the last two rounds at 3p. With C1's correction the budget is
~10^5-10^6 nodes and bounded endgame search fits, so ADR-0013 cannot open
with "exhaustive is impossible, therefore determinized sampling" --
especially as sampling carries strategy fusion that exhaustive search does
not.
C3: the finding failed the admissibility rule this project wrote nine
hours earlier. 6/9/12 are sums where GROUND-WP-0004 T02 requires
per-priority rows, and the harness has no assertions, no --self-test and
no make target, so nothing can turn it red -- a `default` artifact wearing
a `counterexample` label, by CB-WP-0022 T05's own distinction.
C2: the ratio story explains nothing; 3p and 4p share deal, threshold and
ratio and differ by 12.5 points of win rate. C5: "explains the
maintainer's report" is contradicted by lib.rs:2487, which records his
losses as 3-player games on the pre-ruling deal, arithmetically unwinnable
at 6 against 7.
T06 exists to report to GROUND-WP-0005, which is BLOCKED waiting on a
difficulty baseline. Had this proceeded they would have been invited to
move thresholds on the strength of one bot's behaviour. That is the fifth
wrong premise this project would have sent them, and the second stopped by
an adversarial review rather than by a control. Both tier-L reviews here
have now caught a false headline that every gate passed.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
CB-RES-0008 with a runnable baseline
(games/ground/examples/difficulty-baseline.rs), and the measurement
produced a finding before any solver exists.
A GREEDY BOT WINS 200 OF 200 GAMES AT FIVE AND SIX SEATS. Median margin
+3, 11.8-12.0 points available against a threshold of 9. The curve is
66% / 82.5% / 95% / 100% / 100% across 2/3/4/5/6 seats.
Row-level, as GROUND-WP-0004 T02 requires: available points 6 / 9 / 12
against thresholds 5 / 7 / 9, so the ratio RISES with seat count (1.20,
1.29, 1.33) while the table also gains actions per round to clear it with.
Three multipliers pointing the same direction.
It also explains the maintainer's report without needing a solver at all:
"I felt it was too easy but then we lost" is two true statements about
different seat counts.
Cost measured and it rules out the obvious approach. Branching is small
(mean 4.7-9.1) but legal_commands costs 112-161 us per call because it
filters candidates through full validate. Exhaustive search is out at
every seat count; 10^4-10^5 nodes is 1.4-14 seconds, which is the budget
the ADR must design inside.
Prior art names the trap: determinized search (PIMC) suffers strategy
fusion (Frank, Basin & Matsubara 1998) -- the search picks different
actions in states a real player cannot distinguish, so the witness may
require knowing what was on top of the deck. Such a line still replays
green, so the checkability benchmark does not catch it. Honesty and
checkability are different properties; stated explicitly so T03 cannot
conflate them.
The survey states its own most likely killer up front (§6): a view-only
search cannot fold events, so making the information boundary structural
rather than a promise may not be affordable. Better found here than in
T05.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Four of the maintainer's five playtest remarks. Three of the five turned
out to be data the projection already carried, rendered as text -- the
table's problem was legibility, not content, and the coverage gate passes
either way because it proves nothing is OMITTED, not that anything is
readable. That gap is named in the evidence rather than closed: the honest
control is a person playing it.
T01. The ending control was two defects wearing one button. The label said
"close -- I have read this" while hotseat.rs reads `done` as STOP THE
SERVER, and acknowledging it changed nothing -- the tab kept a full table
and a `play again` pointing at a closed port. Now labelled by its effect,
and the page seals itself on the `closed` reply: removeAttribute on every
control's data-drop, so they stop being droppable by the same rule that
made them droppable. removeAttribute rather than setAttribute(_, null),
which writes the truthy string "null" in a browser.
The reason it survived is structural. jsrun's fetch stub returned
{then: function(){return this}} and never invoked its callbacks, so every
line of the script reacting to the server was unreachable from every test
in this project -- a page that ignores the server was indistinguishable
from one that acts on it. Same finding as CB-WP-0016's "a stub too thin to
express a failure is how the failure survives", one layer deeper, at the
reply. The stub now delivers a real then-chain; gesture_with_reply reports
surviving controls; the seal is mutation-proven and a negative control
asserts `ok: dealing` does NOT seal.
T02. Draw and discard as offset stacks with counts. The shuffle question
the task required settling: it already works, at
games/ground/src/lib.rs:1419-1435, implementing the U4 default that
ground-game confirmed 2026-08-03. Nothing raised. The piles show the state
before it fires, which is derivable from the view; a claim that a
reshuffle HAS happened is not, and is not made. CB-WP-0026 applied that
ruling the same day this consumed it -- first time answering "is this
underdetermined?" was one lookup instead of a message.
T03. Each seat's play drawn as a card, sentence kept beside it. The
face-down back is a const with no parameters: SelectionView::Hidden
carries nothing, so there is no data path into the back to add later. The
leak test copies view.rs's own shape -- identical backs across two
different hidden situations, THEN assert a revealed play does show,
because without the second half the first passes for a renderer that draws
nothing.
T04. MatchTally lives in `play`, beside the listener and the seed. What
"cumulative" means was decided before anything was summed, and the answer
is that GROUND defines one game and no series: summed personal score and
games-won answer different questions, and a test asserts they can point at
different seats. Both shown, both labelled. Registered F15 as a NOTE --
the test shows the tallies can differ, which is arithmetic, not evidence
the ambiguity harms play, so GameDesign §3.1 bars reporting it. First use
of the note tier since D6 wrote it, and it came from building rather than
from play.
make all: exit 0. 41 render tests, 26 cb-play tests, loop-lint clean.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
T01. The maintainer asked why the button says "I need to read this" and
why nothing closes. Two defects behind one control: the label described a
reading while the control STOPS THE SERVER (hotseat.rs reads `done` and
breaks its loop), and acknowledging it changed nothing on screen -- the
tab kept a live table and a `play again` pointing at a closed port.
Label is now "end session -- stops the game server". The reply says the
session has ended and the tab can be closed. The script seals the page on
a `closed` reply: removeAttribute('data-drop') on every control, so they
stop being droppable by the same rule that made them droppable. CSS is how
that reads, not the mechanism. removeAttribute rather than
setAttribute(_, null) -- the latter writes the truthy string "null" in a
browser, so the control would stay live while the stub called it sealed.
THE REPLY PATH HAD NEVER BEEN EXECUTABLE IN A TEST. jsrun's fetch stub
returned {then: function(){return this}}, which never invoked its
callbacks, so every line of the script reacting to the server was
unreachable from every test in this project. That is why the defect
survived: a page ignoring the server looked identical to one acting on it.
The stub now delivers a real then-chain and gesture_with_reply reports
which controls survive. The seal is mutation-proven -- deleting the
`closed` branch turns exactly one test red -- and a negative control
asserts an `ok: dealing` reply does NOT seal, since a seal that fired on
every reply would pass the first test and break `play again`.
T02. Draw and discard drawn as offset stacks with their counts. The
shuffle question the task required answering is settled and the answer is
that it already works: games/ground/src/lib.rs:1419-1435 implements the U4
default -- deterministic reshuffle of the discard seeded from seed ^ round,
skip the draw if both are empty -- and ground-game CONFIRMED U4 on
2026-08-03. A ruled rule, not an invented one, nothing to raise. The event
already reads out in the log; what the piles add is the state before it
fires, which is derivable from the view. A claim that a reshuffle HAS
happened would not be, and is not made.
The coverage gate caught its own probe going stale when the "17 remaining"
text was replaced. The count now lives in the pile's <title> -- a stable
probe and what a screen reader announces, where the on-canvas numeral
could be any number on the page.
39 tests pass; cb-play 22 including play_again_deals_a_second_game.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
ground-game ruled all ten U-items on 2026-08-03, every one CONFIRMED as
the default clay-borg simulates, and confirmed five of six provisional
scenarios. clay-borg never collected the answers: CB-RES-0007 reported "0
of 10 ruled" the same day, and CB-WP-0022 built the finding register two
days later still recording them as `reported`. make design's first run is
what noticed -- not a human, not the adversarial review that found four
other things.
That is the unread-inbox failure running in the opposite direction, and it
appears nowhere in the declaration, survey, ADR or spec of the pass that
was built entirely around the forward version. It is arguably worse: an
unread message is visible as silence, while a collected-but-unapplied
ruling looks exactly like work in progress.
Ten rulings quoted into §Underdetermined (the three conditional ones
verbatim -- U1's designer note, U2's End-only trigger, U8's
consume-only-if-it-cancels). Five provisional flags lifted, replaced by
ruled/ruled_by/ruled_note so the flag went and the provenance stayed.
Register queue 9 -> 0.
T02's control came back clean: make sim is 26 passed, 59 rules covered,
nothing red. Had a scenario gone red it would have meant we described our
own behaviour incorrectly to ground-game.
I wrote two U-item mappings and both were wrong. gr-a04 -> U1 (it asserts
consent is REQUIRED; U1 asks WHEN the target accepts) and gr-d05 -> U5 (it
exercises the UNREJECTED Reverse; U5 is the rejected one). Both plausible
from covers:, neither survived reading the description. Third and fourth
instance of this defect; the first two reached ground-game. So encodes_u_item
is now a declaration and design.py asserts the file names what it claims --
and that check's own first version grepped for mentions and went red when
two files recorded why they do NOT encode U1 and U5. A mention is not a
claim, which is exactly the looseness that let "six of the ten have
provisional scenarios" stand.
Two positive controls went red for the best possible reason, both broken
the same way -- asserting against live repo data instead of constructing
their condition. rule-coverage.py required at least one provisional item
to EXIST; it now builds a fixture and reports the live count as a
diagnostic, because there is no number of provisional items this project
should have. design-baseline.py pinned "2 of 6" while recomputing one row
from a live glob, so the dated snapshot was never a snapshot; frozen to
its 2026-08-03 list and unwired from self-tests, since per ADR-0012 D8 it
is no longer a reporting tool.
ScenarioFile is deny_unknown_fields and refused the four new fields until
declared -- correct: a corpus accepting unknown metadata would let a typo'd
encodes_u_iem sit there claiming nothing.
DEVIATION: ADR-0012 D2 said "no new file". GroundRules.md crossed the
loadability limit, so the register moved to specs/FindingRegister.md. D2's
substance holds -- one register, same machinery, nothing competing -- but
the literal instruction did not, and it resolves an awkwardness D2 named
itself.
make all: exit 0. loop-lint clean.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Closes CB-WP-0021, four days after its code landed.
The budget was the wrong one and ADR-0011 corrected it: csv costs 17,651
against AM-4b's 19,742, so it FITS, and was refused on proportion anyway
(89% of the remainder to read 20 rows). Third premise this pass corrected,
second against a mis-chosen denominator. That pattern now has three
instances and no control -- facts-check catches copies that disagree,
nothing catches a number computed correctly against the wrong base.
The hash blast radius was PREDICTED, not discovered. T01's brief required
it be established before writing code and ADR-0011 D3 measured it: 0
scenario files pin a state hash. Verified today, replay-test 14/14 and
AM-7 at 0.985/0.998/1.018 against a 0.9 floor. What actually broke was six
scenarios' data, not any logic.
The endings mean something and they are tight. Played 2p all-bots: total 4
/ threshold 5, group failure, 6 available. T02's control predicted a full
clear is required at 2p and play confirms it -- leaving any single Problem
unclaimed loses at two seats.
T04's last bullet cannot be satisfied. cb-cost.py --slug CB-WP-0020 ABORTS
-- no transcripts retained -- and the instrument refusing to estimate is
correct behaviour, so the number is absent rather than wrong. 41.6% of
spend is UNATTRIBUTED. The quote-the-previous-pass rule breaks after about
four passes and needs a bound; this is the first pass where the chain
actually snapped.
loop-lint's own-cost rule caught the first draft quoting this pass's own
cost as final. Marked provisional -- the rule working.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
T05. tools/design.py, make design, and the register in GroundRules.md --
14 rows, no new file, because ADR-0012 D2 made §Underdetermined the
register rather than building one beside it.
Backfill was the test and it caught two things the ADR did not have.
First, a `role` column. The first report alarmed on U2 and was wrong to:
U2's scenario is green BECAUSE the provisional default it documents is
implemented, which says nothing about whether ground-game agrees. GR-E01's
was a counterexample that went green. Same colour, opposite meaning -- a
register that cannot tell them apart either alarms constantly or never.
Only a green counterexample alarms. Folded back into GameDesign §1.3.
Second, it contradicted the survey. CB-RES-0007 said "six of the ten
already have provisional scenarios." Measured -- grep -lE "\bU<n>\b" over
scenarios/ground -- exactly ONE U-item names itself. Five provisional
scenarios exist and four probably encode U-item defaults, but the mapping
is not written down, so it is not checkable. Same defect class as the
wrong premises, found inside the survey that proposed the fix. Now a
reported debt: open, lacking a reproduction: 9, target 0.
design.py carries the control design-baseline.py never had, asserted
directly: a row citing a nonexistent file must not count as reproduced,
using the exact path 2da19a4 deleted -- which the old tool called green.
design-baseline.py is marked superseded rather than deleted; it is the
evidence for how a wrong number got into a survey.
T06. The report is a FILE in ground-game under GROUND-WP-0002, committed
there, with a hub message that only points at it. It asks for no ruling:
it carries GR-E01's withdrawal, our reproduction debt, and two notes that
are explicitly not findings.
And it had to acknowledge something nobody anticipated. GROUND-WP-0002 is
finished -- all ten U-items were RULED 2026-08-03, every one confirmed as
the default we simulate, plus five of six provisional scenarios. The
survey said "0 of 10 ruled" two days later and this register was built
saying `reported`. That is the unread-inbox failure running in the
opposite direction: they answered and we did not collect it. The
instrument's first run surfaced it. They are `ruled`, not `applied` --
lifting the now-settled provisional flags is owed and is not done, and
make design shows them open until it is.
T07. evidence/CB-EV-0021. Two of six catches in this pass came from
execution rather than process (the role distinction from building it, the
ten uncollected rulings from running it), which is InnerLoop §Design
goal's prediction holding.
make self-tests, facts-check, loop-lint: clean.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
loop-lint flagged 429 lines against the ~400 limit, and it was right about
the cause: the T02/T03/T04 completion records restated content that
ADR-0012, GameDesign.md and the challenge/response trail already carry.
Trimmed to pointers plus the one sentence each that is not written down
elsewhere.
400 lines, loop-lint clean. No content lost from the artifacts that own
it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Not a register; ADR-0012 D2 put that in GroundRules §Underdetermined. This
spec says what may go in it, what a reproduction must show, how a finding
dies, and how a trial game is run.
§1.2 is written against evidence rather than principle. A finding must
print the rows behind any number it claims, and the spec carries the table
of what shipped instead: a sum ("12 in the file"), a green scenario
("4/6/9 against 5/7/9"), and a condition named without checking which one
fired ("SOLVE on a face-down Problem"). "12" was arithmetically defensible
and still wrong about the game -- that sentence is the requirement.
§1.3's target is 0 reproductions that have gone green while open. GR-E01
would have tripped it four days before a human caught it by hand.
No baseline rate is quoted. The 33% was withdrawn by C2 and the first
honest denominator is T05's backfill; quoting a new number from a
discredited instrument is how the first one got in.
The trial protocol costs one flag: cb-play --record already writes a
finished game as a scenario, so a trial is that plus a sibling .md in the
player's own words. An observation is a NOTE until it has a reproduction,
and notes may not cross the repo boundary and expire at 30 days on the
existing provisional-age machinery. The maintainer's "I felt it was too
easy but then we lost" is the case the protocol is shaped around --
forcing it into a schema at the moment of observation would lose it.
loop-lint: no findings.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
one clause short
Nine decisions. Two were not on T03's list; both are the review's.
D2: specs/GroundRules.md §Underdetermined IS the register. C4 pointed out
it was never evaluated as a candidate, and against the survey's own five
benchmarks it already delivers four -- including the Magic Oracle property
("a ruling flips the scenario, not the kernel", :231-233) that the survey
travelled to Magic to discover and we had written down ourselves eight
days earlier. What it lacks is reproductions. So this pass extends a
section rather than building a register: no new file, no new schema, and
no second mechanism to disagree with the first.
D3: admissibility is three clauses. It exists; it has the ruled shape
(GROUND-WP-0004 T02's row-level table, never a sum -- promoted from a T04
addendum because two of three wrong premises were sums without tables);
and it CAN FAIL. The third is C1's. GR-E01's scenario went green when the
edition landed, and the finding stayed admissible and stayed queued for
transmission, because nothing in the rule said a passing artifact was a
signal. A green reproduction is an alarm, not a reassurance.
D1 applied: INTENT gains a fourth property, Instrument, worded as a
mechanism rather than an ambition and carrying its own falsifier -- if a
pass tolerates an undecided rule by quietly picking a default, the
property is false.
D4 five kinds, each forced by an existing finding; a sixth during backfill
means the taxonomy was invented. D5 lifecycle where `applied` means the
source changed, the queue empties while the log accumulates, and
withdrawals are reported rather than deleted -- GR-E01 is why. D6 notes
admitted but never reportable, 30-day expiry on the existing age
machinery; refusing them would discard the only class of finding the
engine cannot produce itself, which is CB-WP-0025's whole input. D7 no
engine-evolution register, on an inventory C5 corrected -- narrowed, not
settled. D8 design-baseline.py retired, kept as a dated snapshot because
deleting it erases the evidence for how 33% got in. D9 the artifact stays
here, ground-game gets a generated file under its own workplan.
loop-lint: no findings. facts-check: no findings.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
First adversarial review in this repo run by a genuinely separate agent.
CB-RES-0006's reviewer opened by conceding it could not be, and called its
own findings "a lower bound on what a genuinely separate reviewer would
find." This is the measurement: the separate reviewer ran git log against
the survey's central example and found 2da19a4 had falsified it four days
earlier, while the author -- who wrote that commit -- quoted the dead
number twice.
Seven challenges: four conceded, two conceded in part, one answered.
C1 changes the design. "GR-E01 is admissible because 4/6/9 against 5/7/9
is a computation anyone can rerun" was a computation already rerun: the
edition import measured 6/9/12, the conclusion inverted, and the scenario
was renamed -unreachable- to -reachable-. That finding was one of the TWO
that passed the reproduction rule. So three wrong premises have now
reached ground-game and the third satisfied an existence test -- existence
is not the property that was missing. The rule gains shape (ground-game's
row-level deal table, promoted from a T04 addendum) and a clause the
survey never contemplated: a reproduction must be able to fail. Ours went
green and stayed admissible.
C1 also caught a defect in flight. T06's payload, status todo, still named
4/6/9 and was queued to send it to ground-game as "no dataset reconciles
them." Withdrawn before sending -- the fourth wrong premise, and the only
one stopped.
C2 withdraws the baseline's precision: design-baseline.py is a
hand-maintained dict counting itself, has_reproduction never checks the
file exists (its YES-control is green against a deleted path), and
Makefile:127 runs only --self-test so the reporting path has no CI. The
direction survives; 33% is not a measured rate and T05 must not build on
it. C3: "six provisional defaults" is five, GR-E01 double-counted. C4:
GroundRules §Underdetermined was never evaluated as a candidate and
already delivers four of five benchmarks -- T03's burden flips to arguing
extension over replacement.
Survived: the rule's affordability, and reuse of the provisional
machinery.
loop-lint: no findings.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Five remarks from the maintainer's test games, checked against the code
before being written down — two had already reached ground-game on wrong
premises, so a claim now names the line that makes it true.
Three of the five turned out to be data the projection already carries,
drawn as text: solution_deck_len, solution_discard, and OutcomeView's
personal/mastery/winners. One control (`close — I have read this`) is
labelled as a reading but shuts the server down, and leaves a live-looking
page pointing at a dead port. One number does not exist at all: table.rs
loops run_game and keeps only the last summary.
CB-WP-0024 (S, chaos d8=6, declaration 7 of window 2) — the piles and the
other seats' plays as objects on the table, the ending control saying what
it does, and a tally that survives "play again".
CB-WP-0025 (L, chaos d8=6, declaration 8) — "could we have won" and "how
hard is this" are the same search asked twice. Tier L because the
information boundary is the whole design problem: a solver reading
GroundState sees the deck the rules hide, and would tell the maintainer he
could have won by playing a card he had no way to know was there. Also
unblocks GROUND-WP-0005, active with both tasks waiting on a measured
difficulty baseline.
Also: CB-WP-0022 T07's evidence file moves to CB-EV-0021 — CB-WP-0023
shipped CB-EV-0020 first.
loop-lint: no findings.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The row folded a 5,000-event log against a 100,000-event log and compared
throughputs, which confounds 'does cost per event grow with history'
(the property it claims) with 'does streaming a 20x longer Vec cost more
per element' (a memory-hierarchy fact true of any program). It measured
the second and reported it as the first: importing the edition enlarged
the aggregate and the ratio fell to 0.845 with the state bounded.
Corrected to time the SAME 5,000 events on a state at depth 0 and on a
state at depth 100,000. Equal windows, equal event mix, so the only
difference left is history depth.
corrected: clean 1.004, mutated 0.589 (red)
old: clean 0.845 (red on healthy code), mutated 0.751
It also runs in 8.5s instead of timing out: the first version re-walked
the 100k prefix every repetition, 200M untimed folds per sample, which
under the mutation never finished. A control that cannot be run is not a
control. It now advances to depth once per sample and clones.
Two of my own measurements here were wrong and both were caught by
measuring again. A 2-minute timeout killed the shell line before its
restoring cp ran, so three readings were taken on MUTATED code -- I
diagnosed an event-mix confound that did not exist and 'fixed' it. The
fix is kept on its merits; the justification was fiction. And the probe
that proved state was bounded had checked four of eleven collections.
make all exits 0.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
GR-S01 was ruled 2026-08-04: Surface always, union hidden priorities
1..k, k = 2/3/4. So the deal is 3/4/5 Problems, not 2/3/4; available
points 6/9/12; thresholds 5/7/9 stand; SHARED GROUND is 2-6p as printed.
The question CB-WP-0021 was going to send has been answered, and it was
the deal.
CB-WP-0021 is re-scoped. The import is now LOAD-BEARING rather than
merely correct: the ruled 6/9/12 holds only with Problems.csv values, and
the same deal with the stand-in gives 6/10/15 -- a different game that
happens to also be winnable. Fixing the deal without importing the data
would produce numbers nobody ruled on, so T05 (deal) and T02 (import)
must land together. gd0001 is to be INVERTED, not deleted: it is the
record of why this changed. gr-e01 is rewritten as a non-provisional
import check, per the ruling's own wording, and loses its provisional
owner because ground-game has now ruled.
CB-WP-0022 absorbs ground-game's process ruling, which is stricter than
this pass proposed: arithmetic findings need a runnable reproduction AND
a row-level deal table listing Surface and each hidden priority
separately, never only a sum or a deal depth. That is a direct
consequence of both premises we got wrong. So the reproduction rule gains
a SHAPE requirement, not just an existence one -- a finding that ships a
passing test but describes the wrong quantity is still a bad finding, and
that is what happened twice. T02's review brief is flipped accordingly:
press whether the rule is SUFFICIENT, not whether it is affordable.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The AM-1 coverage gate failed the build on GR-P05 being uncovered, which
is what showed the rule was in the offer layer rather than in validate.
A rule enforced only by the offer is enforced only for clients that ask
what is legal. The gate did not catch a bug, it caught a design error.
And the reported case was not the one reported. CB-WP-0018, CB-EV-0016
and the message to ground-game all described SOLVE offered on a
face-down Problem; validate already rejected face-down, so it never was.
Problem 1 is the Surface Problem, face-up from the deal, so the three
inert SOLVEs were the HAND case. The ruling covers both so nothing is
invalidated, but a ruling was requested on a wrong description -- the
second time in three passes that a premise reached ground-game
unchecked, after the '12 points available' that voided GR-E01.
Two of two. The pattern is not careless analysis; it is that a claim gets
SENT the moment it is interesting and checked afterwards. Unexecuted
verification, one step further out: not a belief acted on, but a belief
published. CB-WP-0022's reproduction rule would have caught both.
An earlier mutation run reported three survivors and was wrong -- the
replacement strings did not match, so nothing was mutated. It proved
nothing and looked like a result.
Also renames CB-WP-0022-T06B to T07; the hub flagged it as an
unregistered species.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Implements ground-game's ruling of 2026-08-03. make all exits 0, 26
scenarios, rule coverage 59/59, and no scenario encoded the bug.
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. A rule enforced only by the offer is enforced only for
clients that ask what is legal -- the browser would be filtered and a
scenario file would walk straight past it. Once GR-P05 moved into
validate, every condition in legal_commands was dead code, and the
layering test said so in those words.
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, 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.
Four conditions asserted separately, because one 'SOLVE is filtered' test
would pass with three of four implemented.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
ground-game ruled SOLVE's legality on 2026-08-03: not offered on a
face-down or Denied Problem, not offered without a matching Solution in
hand, and not offered on a Problem claimed in a prior round. The bluff
reading CB-WP-0018 raised is dead -- it was a filter bug, and the engine
has been offering an inert move since legal_commands was written.
Only SOLVE is ruled on, so only SOLVE is touched. Implementing more than
was ruled would be inventing rules, which is what this exchange exists
to stop.
Chaos d8=6, no override.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
CB-RES-0007 plus a runnable baseline harness. Tier L invokes the
runnable-baseline option; the external candidates are practices rather
than software, so their rows are directional and cap at parity, and the
row that CAN be run is our own.
Measured: 6 findings across 11 files with no index, 2 of 6 (33%) with a
runnable reproduction, U1-U10 raised 2026-07-30 and first READ
2026-08-03 -- 4 days, 0 of 10 ruled.
The uncomfortable number is stated before the review can find it: the
proposed 'no finding without its reproduction' rule would reject four of
our six existing findings. The survey answers rather than routes around
it -- none of the four is expensive to reproduce, so 33% is evidence
nobody was ever asked for one.
Magic corrected an assumption this pass was about to build on. Rulings
are NOT authoritative -- they are 'reminder information with no actual
weight or rules meaning' -- and the authoritative fix folds into the
Oracle card text. So a finding closes when the SOURCE changes, not when
an annotation is added, and the register must be a queue that empties
rather than an archive that grows. That is now a constraint on the ADR's
lifecycle.
Model checkers supply the reproduction rule independently: a
counterexample trace IS the finding. W3C's implementation-defined mark is
the machinery we already have in provisional: scenarios and must reuse.
The loop-lint gate caught the new tool with no --self-test; it has one,
pinning the 2-of-6 baseline so a later edit cannot move it silently.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The maintainer named a new aspect: clay-borg as a game design tool, with
a register for design flaws, questions, results and trial protocols.
Structural L on the maintainer-named-high-leverage trigger, and it amends
INTENT. Chaos d8=6, no override.
The insight is that this is already happening with no home. Five passes
have produced ten underdetermined rules points, SOLVE offered on a
face-down problem and always inert, GR-A13's wasted SOLVE, GR-E01
unreachable below 5 seats, six provisional scenario defaults, and two
scoring modes never played to the end -- every one found by BUILDING the
simulator rather than by playing it. A simulator rigorous enough to
refuse ambiguity is a design instrument, because it cannot proceed past a
rule that does not decide. All of it has been carried in prose in six
places and one sat unread in an inbox for four days.
The load-bearing rule: a design finding is not admissible without its
reproduction. A register that collects opinions would reproduce this
project's standing failure -- unexecuted verification -- in a new medium.
Recorded as a judgment for the adversarial review rather than assumed:
the engine-evolution meta the maintainer also asked about should NOT be
built, because evidence/, decisions/, gates.toml and workplans already
carry nineteen passes of it with dates, costs and falsifiers. A second
register for the same subject is ceremony. The asymmetry is the point --
engine evolution has a home and game design does not.
T05 backfills the six known findings as the TEST of the register: one
that cannot express findings the project already has is the wrong
register, and discovering that after designing it is why the order is
survey, review, decide, specify, build.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The declaration claimed importing the edition data would resolve GR-E01.
Measured across all four scenarios: GR-S01 deals 2/3/4 problems by player
count, not all five, so 4/6/9 points are in play against thresholds of
5/7/9 -- unreachable at 2p and 3-4p with the REAL data, in the same shape
as the stand-in's 3/6/10. So GR-E01 unreachable below 5 seats is a real
property of the game and gr-e01-threshold-unreachable-2p asserts
something true.
The error was the cheap kind: 12 points exist in the file, so I assumed
12 are in play. One command over the CSV settled it and was not run until
after the declaration was committed -- this project's characteristic
error, in the pass that followed a ruling obtained because of it.
CB-EV-0018 corrected too: 'confirmed as the stand-in's doing' was
overstated. The zero came from no Problem being claimed at all.
T03 now owes ground-game a sharper question than a retirement: either
GR-S01's deal count is wrong or GR-E01's thresholds are, and no dataset
can reconcile them.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
GROUND-WP-0002 T01 ruled the edition dataset authoritative, so the engine
must stop inventing Problem values and suits. Problems.csv carries 5
problems per scenario worth 2,2,2,3,3 (total 12) with a required_solution
each; the stand-in deals 3 worth 1,2,3 (total 6). GR-E01's thresholds of
5/7/9 are ordinary against 12 and unreachable against 6 -- which is why
the maintainer's last game ended 0 scores and winners nobody, and why
'GR-E01 unreachable below 5 seats' was carried as a rules gap. It was
never a rules gap.
Measured before declaring: AM-4a has 3,798 lines of headroom and a CSV
crate costs 21,613 marginal (csv 14,291 + csv-core 3,360 + ryu 3,962;
itoa/memchr/serde/serde_core are already present and free). 5.7x over, so
the shipped runtime cannot gain a CSV parser and that is settled by
measurement rather than preference.
The ADR's third question is the one that bites: Problem values and suits
become part of GroundState, which is hashed, so every recorded state hash
changes. A content import that quietly invalidates every hash in a
project whose central invariant is replay determinism is not a
data-loading change.
Chaos d8=7, no override.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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>
The perceptual check found seven items; item 1 passes. Chaos d8=8 fired
the FIRST override at the new rate, on the second roll, and drew S --
which is what the structural derivation said, so it changed nothing.
That is one half of window 2's retirement condition (retire if an
override changes nothing twice running).
The maintainer's design instruction is adopted directly: a legal drop
target should change its EXISTING border to dashed rather than draw a
new outline. That explains the hidden top/left edges (an outline on an
SVG <g> is clipped by the viewport) and the oversized seat highlight.
The ghost is a textContent copy, which is why the linebreak collapses and
it reads as a second card, and why showing the explanation destroys the
label -- one cause, two reports.
T03 carries an explicit instruction not to fix a message that already
works: the 'nothing droppable' path may simply be unreachable because
almost every part of the page is a card. Reproduce before changing.
T05 records that 0 scores and no winner is very likely the stand-in
dataset rather than a scoring bug, now that GROUND-WP-0002 T01 has ruled
the edition data authoritative. The import is its own pass.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
T03: InnerLoop v1.7 plus loop-lint's own-cost check. Six passes
under-reported themselves by 30-45%, never once high, and the rule lived
only in evidence files having been re-derived three times. The READING
is load bearing, not the boundary: CB-WP-0018 T04 applied 're-run the
instrument at the moment of quoting' alone and its figure was correct.
So the operative instruction is re-run when you quote, and loop-lint
fails an evidence file naming its own workplan beside a dollar amount
without marking it provisional.
It binds forward from this pass. The check fires on seven historical
files which ARE the evidence for the rule; making them comply would edit
the record to remove the thing it proves -- the same category error as a
live fact: tag on a dated measurement, which this pass also hit.
Lifecycle, at the maintainer's instruction: ready -> active -> done,
where ready means declared and not started. loop-lint fails a workplan
that has started and still says ready, one that is active with
everything closed, and one that is done with an open task. The first
version of that check was WRONG and its own self-test caught it: it
stripped the leading status: assuming frontmatter, which silently
dropped a real task once the frontmatter said ready or active.
Both new checks then fired on this pass's own artifacts and both were
right to.
T04: CB-EV-0017. The new meta budget's first reading is a breach it
caused -- 27% against the 20% line, because this pass cost $31.18
against product passes averaging ~$21. Reported rather than exempted:
ADR-0006 D2 covers the instrument repairs but not the rule-writing, and
the honest reading is that this should have been two passes.
CB-WP-0018 settled at $36.53/95 against $28.08/82 last reported, 30%
higher. Seven for seven.
make all exits 0.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The two AM-4 budgets had the SAME scope -- one package, no dev edges --
while claiming to bound different things. AM-4b now measures the
workspace with dev edges: 57 crates / 725,258 lines where it read 29 /
317,021, having been blind to 28 crates and 408,237 lines, more source
than its own target.
Target 745,000, ~2.7% of room -- the same margin ADR-0008 D3 gave AM-4a,
applied to a number that grew because the instrument was repaired, not
because anything was added. The target moved to fit the measurement.
T02: proc-macros are COUNTED here and excluded from AM-4a, on purpose.
AM-4a asks what ships and a proc-macro never ships. AM-4b asks what is
acquired, and ADR-0007 D3's acquisition rule counts what the build
fetches -- 'it does not ship' is no answer to 'we downloaded it'. When
the rules disagree, the question each budget asks decides. Measured
share 109,585 lines / 15.1% against AM-4a's 36.2%, so ADR-0008 D2's
refusal to borrow the ratio was right by more than a factor of two.
Caught by this project's own earlier work twice: the mutation
find-string went stale and --self-test reported it BUILD-FREE (the check
CB-WP-0015 added after AM-4a's rotted for two passes), then the DFD gate
caught facts.toml carrying the old numbers.
CB-EV-0001 and ADR-0004 carried live fact: tags on historical readings.
A dated record asserting a CURRENT value is a category error, so those
occurrences are marked as-measured instead of retro-edited, and ADR-0004
gains a supersession note.
make all exits 0.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
InnerLoop v1.7. The purpose is written first and the number follows from
it: most spend on the task at hand, some on control, review and
improving the process. make status prints it above the figure, because a
threshold with no stated purpose is what let this number be argued three
times.
Soft 20% over a trailing 5, and the self-test enforces that the ratio and
the window are a PAIR: META_SOFT_PCT == 100 / TRAILING_PASSES. One meta
pass among n at parity cost reads 1/n, so 80/20 is one pass in five at
normal cost -- a five-pass window. The same 20% over three would have
silently also demanded the meta pass be half-price, which makes meta work
rushed rather than rare. Moving the ratio without the window goes red.
The phase setting is declared, argued and expiring in gates.toml, and
reverts on review_by unless re-argued. Verified live at 35%. One with no
reason or no expiry is refused rather than honoured, because a threshold
anyone may move is not a threshold.
Measured: the last five passes read 7% against the new line.
InnerLoop.md crossed the 400-line limit three times while this was
written and was fixed structurally each time -- the arithmetic, the
cost-per-response basis and the two review case studies moved to
InnerLoopReference.md. The limit was not raised.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The maintainer asked for a rule for what the budget is FOR: main spend on
the task at hand, some on control, review and improvement, 80/20 to
start, adjustable by phase.
META-25 has a threshold and no stated purpose, which is why the number
has been argued three times. The purpose goes first.
Recorded in the task: the ratio and the window are a pair. Over a
trailing 3-pass window one meta pass at parity cost is already 33%, so a
20% line there means 'one in five AND half price' rather than 'one in
five'. Over trailing 5, 20% is exactly one pass in five at normal cost,
which is the literal reading of the instruction.
The phase adjustment must be declared, argued and expiring in the shape
gates.toml already uses -- a threshold anyone may move is not a
threshold, and this project fixes limits structurally rather than
raising them.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Both owed numbers measured BEFORE declaring, so the work is scoped
against facts. AM-4b's scope: 29 crates / 317,021 lines instrumented
against 57 / 725,258 real, so 28 crates and 408,237 lines are uncounted
-- more than its own 350,000 target. AM-4b's proc-macro share: 109,585
lines, 15.1%.
That 15.1% vindicates ADR-0008 D2, which refused to correct AM-4b using
AM-4a's measured 36.2% because 'correcting a second instrument on the
strength of the first one's ratio is the error this change exists to
fix'. Borrowing would have been wrong by more than a factor of two.
Also carries the self-quoting rule, which is six-for-six under-reported
by never less than 30% with both causes diagnosed, and still lives only
in evidence files.
Structural tier M: changes a budget's scope and target and a reporting
rule. Chaos d8=5, no override -- the first roll at the new rate.
Declaration 2 of window 2. Meta budget 0%; ADR-0006 D2 exempts
instrument repair regardless.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
T03: input::describe writes a sentence per legal command; data-descs
carries them in step with data-targets; the ghost already following the
pointer shows the one for whatever legal target is under it, so the
explanation lands beside the target with no overlay layer to keep
aligned. ADR-0010 D1 binds -- the page renders it, never composes it.
Both mutations INITIALLY SURVIVED because the fixture's Attack card had
exactly one target, where an off-by-one shift and a truncation are both
no-ops. CB-EV-0014's lesson one level in: a fixture too thin to express
a failure is how the failure survives. Two attack targets now, both red.
T04: chaos rate d4 -> d8, window 2 open at 12 declarations, retiring if
an override changes nothing twice running. Window 1's condition was NOT
met -- both overrides changed the outcome -- so the mechanism is kept.
The weakest part of the decision is that it is a rate change argued from
n=2, so window 2 carries a falsifier: no override at all is evidence the
rate went too far, not that the mechanism is healthy.
InnerLoop.md hit 401 lines and the loadability gate fired; the rationale
moved to InnerLoopReference.md, structurally, per the standing precedent
that limits are not raised.
CB-WP-0017 settled at $9.48/40 against $5.19/23 reported mid-flight,
83% higher. Six for six, always low -- read by re-running the instrument
at the moment of quoting, which is CB-EV-0015's correction applied for
the first time.
make all exits 0.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>