75 commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
| 704b99975b |
Apply ground-game's rulings: mastery in points, four boards, and a
Some checks failed
ci / check (push) Failing after 4s
vendor tool that covers what the gate checks
They ruled on all seven items the same day. Two were actionable here.
F28 RULED: points. Modes.csv MODE_COOP clarified upstream to say
"penalties apply to points, not card count"; mastery is now
total - blame - denied. A recorded scenario went red on it --
gr-e02-shared-ground pinned 0 (2 claimed CARDS - 1 - 1) and now expects
2 (4 POINTS - 1 - 1). The number moved because the rule was decided, not
because the engine drifted, and the scenario records both rulings; its
schema has no field for a second one, so both live in ruled_note with
`ruled` carrying the LATEST date.
F29 RULED not-intended and APPLIED upstream: SCN_02's suits re-tuned the
same day. The characterisation test is how we found out -- it pinned the
duplication, went red on the re-tune, and that red WAS the notification.
It now asserts every pair distinct, the stronger statement the
duplication had made unavailable. SCN_02 re-measures at 73 at 2p, not
67: its own board now.
F26/F30 ruled and recorded. F30's ruling incidentally confirms our
reading -- they name priority-2's suit as the first lever, which is the
difference we identified without having measured causation.
vendor-editions grew twice, both times because it covered less than the
gate it exists to satisfy:
- It refused to touch ground-darvo-r0/ on the reasoning that the
baseline is "a separate record". That was wrong within the hour:
ground-game clarified Modes.csv and `make vendor` reported a clean
sync while edition-check went red. A sync tool that covers less than
its check reports success into a red gate.
- Its two-block rewrite DETECTED which fence held which set and
preserved the arrangement -- faithfully preserving a swap an earlier
write had introduced, leaving each fence under a heading describing
the other. edition-check reads every sha256 line flat and passed
throughout: a document can be self-consistently wrong and green.
Order is now asserted, with a control that goes red on a swap.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
|||
| 0b8599bd88 |
CB-EV-0033 + GROUND-RPT-0006: report the boards and modes to ground-game
Some checks failed
ci / check (push) Failing after 4s
Five things worth their time, four of them asks rather than statements: F29 SCN_01 and SCN_02 are the SAME BOARD -- identical suit and value at every priority, every cell matching exactly. Not called a defect (a reskin is legitimate) but "four scenarios" is three boards. Asked whether it is intended. F30 SCN_04 is materially harder at 2p: 52/100 against 67 and 73, with every other parameter held by the edition itself -- same deal shape, same 6 available points, same threshold, same starting Stress. The lone difference is that it is the only 2p deal needing two of one suit. Causation explicitly NOT claimed; the falsifier is stated. Sensitivity: at 4p SCN_04 is 97 against 94/99, so it is not the hard board there. The modes finding, corrected in their favour: we previously reported the three modes produced identical play. That was OUR INSTRUMENT, not their game -- the bot never read the Mode card. With a mode-aware bot, group success is unchanged in 34 of 36 cells but coalition size moves by half again at 4p. So the modes decide the distribution of the win and the threshold decides survival independently of it. F28 (mastery counts cards where the shared score counts points) and F26 (a package that adds a FILE is invisible to a consumer) promoted to reported -- both need their ruling, neither changed on our side. F17 and F26 move raised -> reported now that they are in a delivered report. The register crossed the ~400-line loadability limit, so prose for CLOSED findings moved to FindingRegister-closed.md. The rows are untouched and `make design` still reads one file -- ADR-0012 D5's reasoning about mixing open and closed applies to files too. Report left UNCOMMITTED in ground-game: their tree has live uncommitted work from their own agent. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
|||
| 3045eb03f8 |
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>
|
|||
| bff64053ca |
ADR-0022 + CB-WP-0048 T00: the selector decision, and the mirror held
The maintainer's observation decided the design: aspects partition the GAME, strata partition our apparatus, and they are orthogonal. A module is one coordinate change in aspect space with an obligation in every stratum. So aspect identity must NOT be Rust types -- an aspect ground-game adds would make clay-borg fail to parse a configuration rather than fail to run it, welding the two coordinate systems at the one place they must stay independent. Chosen: identity as data (Configuration round-trips anything the catalog names), behaviour exhaustive (Rules, no catch-all), resolve() between. Decisive argument: the catalog ALREADY ships modules with a rules_delta and status: proposed, so a per-aspect enum would report them as "unknown module" -- indistinguishable from a typo, a false statement about the edition, and this project's signature failure shape. Two facts need two errors. Federating design authority is permanent, so the representation must outlive the implementation. Legacy ids alias forever through the catalog's own legacy_experiment_id, on the standard-Np precedent: 26 recordings name them and the expansion is exact, so there is nothing to deprecate. T00 done: the schema-2 mirror had arrived with no digests (19 files) and edition-check was red. Digests are now generated by WALKING editions/, not typed -- two reviews already found hand-written lists that made their own controls vacuous, and a mirror that grows a directory is what breaks a maintained list. PROVENANCE-catalog.md was a file inside the mirrored tree that upstream does not have; folded into our own PROVENANCE.md, since provenance about the mirror does not belong inside the thing it describes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
|||
| d30938b259 |
CB-WP-0047: all four boards, and every mode named on the page
Some checks failed
ci / check (push) Failing after 3s
The modes were already implemented; nothing had ever COMPARED them. The scenarios were not implemented at all: edition::deal has taken a scenario_id since it was written and the only caller passed the literal "SCN_01", so 15 of 20 Problem cards had never been dealt by anything. The seam was the whole mechanism and it sat unused, with nothing red because nothing asked. Scenario is now state (serde default SCN_01, so all 26 recordings replay unchanged), selected by preset `scn-03-4p` with `standard-Np` still meaning SCN_01, and by --scenario/SCENARIO= accepting ids, numbers or titles, validated against the edition rather than a pattern. The threshold now comes off the Scenario card, closing F25's hardcoded 5/7/9. The first version of that control was worthless and mutation said so: all four scenarios print 5/7/9, so reverting to the bands left it green. Split threshold_from() so it can be handed a card that disagrees. The header read `scoring CommonProblem` where the Mode card is titled COMMON PROBLEM, PERSONAL EDGE -- the defect CB-WP-0034 deleted from the move buttons, still standing on the line that says what winning means. The coverage probe was matching that Debug output and went red when it was fixed: third instance (CB-WP-0024, CB-WP-0034). Page now carries the premise, the mode's rules text, and the tiebreak. scenario-panel plays 4x3x3. Findings: SCN_01 and SCN_02 are the same board (identical cells, pinned by a characterisation test); SCN_04 is the hard board at 2p (52% vs 67/73%, the only deck needing two Repair); and group success is EXACTLY equal across all three modes in all 36 cells, because greedy never reads state.mode -- filed F27, the two competitive modes are scoring lenses over cooperative play. F28: SHARED GROUND's mastery subtracts penalties from the claimed COUNT where the mode card's shared score is claimed VALUE. Raised, not fixed; scoring is ground-game's to rule on. Also fixes design.py reporting a backticked path as no reproduction. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
|||
| de25c4cae0 |
CB-WP-0046: the rule the placement encodes, and a log that names its rules
Some checks failed
ci / check (push) Failing after 4s
CB-WP-0045 left "nothing explains what a scope does" open and gave a FALSE reason: that scoping is our Variant so no printed sentence exists. The H2 package ships Rules_Text.csv -- twenty-two passages of player-facing rules -- and nothing in clay-borg had ever read the file. A wrong reason for an open item is worse than an open item; it retires the question. Filed as F26 against ground-game: a package that adds a FILE is invisible where one that adds a column is not. The scope rule now renders under the table in the edition's own words, only when a non-global scope is in play, matched by heading rather than row number, and absent (never paraphrased) if the edition drops it. The trial log stamps its variant on the begin marker -- a session property, not an eighth column -- read off state.variant rather than the --variant flag, because a bare `state.variant = v` leaves H2 inert and a flag-stamped log would put false provenance on real player words. An unstamped log reports `unrecorded`, never `ground-darvo-r0`. Six mutations, six red. The sixth is the finding: every trials.py fixture built its marker out of BEGIN, so nine checks followed BEGIN away from what hotseat.rs writes and stayed green while real logs broke. A fixture built from the constant under test cannot test the constant -- the control is now a literal, asserted from both sides. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
|||
| 05d1a9aada |
ADR-0021: the chaos roll is retired, and the condition that retired it was wrong
Some checks failed
ci / check (push) Failing after 4s
The condition is met and the tally was verified rather than recalled. ADR-0017 D2 named window 3 as the decider; windows 2 and 3 each produced exactly one override and each changed nothing. Every roll in window 3 was cross-checked against the workplan that made it, because the last time this project tallied chaos rolls from memory it was wrong and asserted the wrong figure four times (F23). All twelve agree. But meeting the condition is not evidence. P(an override changes nothing) is 1/3, and each window had exactly one override, so the condition fires on a 1/9 coincidence. ADR-0017 restated it to be REACHABLE and made it weak in the process; reachability was checked and discriminating power was not. Worse, it measures the wrong subject. It asks whether an override changed the tier; the question is whether changing the tier helped. Under it, a die that always changed the tier could never be retired however useless its changes were. The real ground is stronger. Four overrides across roughly forty declarations, and the mechanism's value has never once been demonstrated. The one substantive intervention dropped CB-WP-0011 from a structural L to S, and that work then needed CB-WP-0016 and CB-WP-0017 to fix defects a human found by playing. Not offered as causation — a tier is process weight, not a guarantee — but it is the only evidence we have about an override's consequences and it points the wrong way. And the purpose has no live evidence of need: 17 M, 11 S, 4 L across every workplan, with the only two structural/declared mismatches being the window-1 overrides themselves. Tier declaration has not ossified. So: retired, with nothing replacing it. Adding a successor to guard against ossification that has not occurred would invent a gate for an instance we do not have. The revival trigger is stated: tiers collapsing toward one value, or a pass declaring below its structural tier to dodge a review. InnerLoop loses the chaos paragraph, loop-lint loses the chaos-recorded check — a check that outlives its rule becomes an obstruction — and its self-test now asserts the opposite: a note with no roll must pass. ChaosRollHistory is closed. Window 4 ends incomplete at four declarations, the last of which is this one, rolled because the rule was still in force. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
|||
| 2806b3acb7 |
CB-WP-0041 done: ADR-0020 refuses the port, and T02 is why
Some checks failed
ci / check (push) Failing after 3s
T02 — all chance derives from one root seed. Three chance points, all reading it: the setup deck shuffle, the setup Lead draw, and the reshuffle permutation. The Problems deal is not chance at all. So in extensive-form terms the tree has a single chance node at the root. That test was wrong first, and the mutation caught it. It compared state hashes — and GroundState carries `seed` as a field, so "different seeds differ" was true by construction. Mutating the shuffle away left it green. It now compares the dealt configuration, and the same mutation fails it: a wrong-subject error inside the control written for T02. The reshuffle is a pure function of (seed, round) because K5 requires deterministic replay, where a real table reshuffles independently. That is a modelling restriction, not a defect, and it is now pinned. T03 — commit/reveal checked in both directions: before Reveal each seat sees its own selection and no other; after Reveal the information sets merge, because an encoding that hides forever is not commit/reveal either. T04 — ADR-0020 refuses the EFG port, and the blocker is T02 rather than T01, which inverts what the workplan expected. Perfect recall looked like the risk and is a constraint with a known answer: key on observation histories. Making chance explicit is the expensive one — the reshuffle would become a real chance node and break the K5 purity that every recording, replay bundle and trial-note hash depends on. A port would trade the property this project is built on for one it has never needed. Track B's first move is therefore a question, not a build: take "is exploitability meaningful for a co-operative game with a shared threshold" to OpenSpiel on a toy model, where answering it costs nothing. D4 states what being wrong looks like — OpenSpiel settling on a toy what three rounds of policy sweeps could not — and makes watching for it the next action. Taxonomy §4.1 records the EFG correspondence with the test that checks each row, so a later pass starts from a specification rather than a memory. Chaos window 4 at three declarations. Window 3's verdict is now two windows behind and should be evaluated rather than restated. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
|||
| 55a475b1a9 |
CB-RES-0009: extensive form is the lingua franca
Some checks failed
ci / check (push) Failing after 4s
Two questions from the maintainer — is there a game-theory mapping to Ludii's language, and is that language formal enough to derive one from. Yes, no, and the no does not matter. The mapping is proven, not to be invented: "The Ludii Game Description Language is Universal" shows the language can represent an equivalent game for any finite, non-deterministic, imperfect-information game, extending earlier work limited to finite deterministic fully-observable extensive-form games. EFG is also OpenSpiel's object, so the same formalism connects description to analysis: Ludii -> EFG <- OpenSpiel. Ludii's syntax is formal and unusually so — a class grammar derived automatically from its source. Its semantics are its Java: a ludeme means what its class does, and Ludii effectively makes Java the game description language. So there is no independent calculus to extract. The formality lives in the universality RESULT, not in a definition of meaning. GDL has the semantics and pays for it in speed — six times on Gomoku, twenty on Amazons and Hex, over two hundred on Chess. Conclusion: do not derive a language from Ludii; target the EFG directly. And we are closer than the tracks assumed. The journal is the history, Outcome is the payoff, legal_commands gives the actions — and project(Viewer::Player(seat)) IS the information partition, built so a player is not shown another's hand and unremarked as exactly the machinery imperfect information needs. Three gaps: chance is folded into a seed so a game is one realisation rather than a game with chance nodes; perfect recall is unasserted, which CFR and exploitability both assume; and commit/reveal is the standard EFG encoding of simultaneity but is never stated as such. Perfect recall is checkable from the journal today and is now Track B's first task — if it fails, every equilibrium concept we might quote is unsound here. Also re-vendored the catalog twice: ground-game added H2 — scoped problem stress, applying End Stress by personal/bond/global scope instead of flat to everyone, which is a direct response to our reading that H1's tax scales with the Problems while its intended effect does not. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
|||
| b590e7fd59 |
simulators/: persist the survey, and let it shrink two of the three tracks
Some checks failed
ci / check (push) Failing after 4s
Eight profiles on a common schema, each marking what was checked against a source this session and what is background recollection. Three are marked unverified in full — Machinations, the play substrates, most of RBG — and say so rather than reading as evaluations. Written straight after three review rounds whose entire yield was claims outrunning what had been checked, so the confidence rule is the first thing in the README. The survey changed the plan, which is what a survey is for. Track C was described in Positioning as open ground. It is not: Browne published 57 criteria for game quality, and Ai Ai already computes designer-facing measures — drama, lead changes, branching factor, completion, duration — from played games. The track becomes adopt, credit and find the gap. The gap looks real: those measures presume a leader, and SHARED GROUND has none — Modes.csv gives its tiebreak as "Not applicable". Track B probably adopts rather than builds. OpenSpiel implements CFR, best-response and exploitability over games that are simultaneous-move, imperfect-information and co-operative, which is all four of GROUND's awkward properties. "Does ATTACK ever pay" is a best-response question, and we spent three review rounds refining a two-policy sweep for it. The first Track B task is now one question — is exploitability meaningful for a co-operative game with a shared threshold — not a build. The cost of not surveying earlier is therefore measurable, and is recorded rather than glossed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
|||
| 713a9df7fd |
CB-WP-0040: name the stratum before naming the defect
Some checks failed
ci / check (push) Failing after 3s
The maintainer could not tell whether "error", "failure", "finding" or "correction" referred to the game's design, our formalisation of it, the code, the measuring apparatus, or the sentences we wrote. Three review rounds produced twenty-odd defect statements spanning five systems, all called errors. The confusion was ours. specs/Taxonomy.md, grounded in named canon rather than invented here: six strata from Sargent's problem entity / conceptual model / computerized model, extended where a simulation-V&V frame stops — we also own an instrument and an account. The two relations are what was missing: GAME<->MODEL is validation, MODEL<->ENGINE is verification, and nearly every argument about "our bug or their gap" was that distinction going unnamed. Fault/error/failure from Avizienis et al., applied within a stratum, plus the rule that explains the review history: a failure in one stratum is a fault in the next. And it finally defines the family ADR-0018 could only point at — a wrong-subject error is an ACCOUNT failure with no INSTRUMENT fault, which is why tests never catch them. MDA supplies the game-facing layers and one hard limit: our panels measure dynamics, our trial logs sample aesthetics, and a win rate does not answer "is it fun". specs/Positioning.md names the field fairly — Ludii is the closest relative and the right benchmark — and the four differentiators, each already built rather than aspired to. Clay-borg is a design-evidence instrument; anyone can produce the number. Three tracks named and none started: a second game, game theory as the lens on dynamics, and assimilated knowledge about why games work. Track A is the falsifier for the whole positioning: every abstraction here has exactly one instance, which by our own rule may mean invented rather than observed. Chaos window 3 closes at 12 declarations with one override that changed nothing. Its verdict is due and is deliberately not written here. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
|||
| 0f64961d06 |
CB-WP-0039: a seat that does not regulate — and it changes H1's verdict
Some checks failed
ci / check (push) Failing after 3s
CB-EV-0030 concluded H1's DARVO arm rate was still 0. That was true of the panel, and the panel was greedy-family throughout. GreedyPolicy ranks `Ground if gated => 100`, so it grounds the instant the stress gate bites, Stress plateaus at 3, and the arm at 5 is unreachable by construction. "H1 does nothing" was really "H1 does nothing to a seat that already manages its Stress" — and H1 was written for the seat that does not. `reactive` is greedy with exactly one preference changed: GROUND demoted below ATTACK. Under it, H1's criteria 1 and 2 are MET — DARVO arms 400 times per cell, ATTACK is chosen 3 times per seat per game. Criterion 3 fails harder: reactive wins nothing at any seat count. The larger finding is about the baseline. Greedy and reactive play IDENTICALLY under baseline, and peak Stress across 3,200 baseline games was 1 — against a starting value of 2. The gate at 4, the DARVO arm at 5 and the Freedom token are all unreachable, and a policy built to be reckless with Stress is indistinguishable from one built to husband it. That is a deeper account of F17 than F17 has. Not raised as a finding yet: it wants the plural panel first. A constant was investigated rather than reported: darvo was exactly 400 in every cell while atk scaled with seats. Six-player final Stress is [5,5,4,4,4,4] every seed — H1-B holds the attacker at 4, below the arm, and pushes its targets to 5. The self-soothe suppresses DARVO in the aggressor and concentrates it in the attacked. The direction follows from H1-B's arithmetic; the number 2 is partly an artifact of reactive's first-legal targeting, and is labelled as such. Still unreviewed: tier L review outstanding on CB-WP-0038, and nothing here reaches ground-game until it runs. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
|||
| a928b5925c |
CB-WP-0038: variant selection, H1 implemented, and H1 measured
Some checks failed
ci / check (push) Failing after 3s
ground-game packages hypotheses as selectable rules variants — a catalog, a rules_delta.yaml, and prose — and their note is explicit that CSV text alone is not executable here. So the kernel gains a Variant in game state: in the state, therefore in the hash, therefore in the recording, because a scenario replayed under a different variant would diverge silently. Baseline is bit-for-bit what it was, asserted across seat counts and seeds. A variant system that perturbs the baseline invalidates every measurement this repo has. H1-A and H1-B implemented from rules_delta.yaml and mutation-proven on their own defects: "unclaimed" misread as face-up-and-unsolved, and the attacker's Stress read after the attack's effects. Their `unchanged:` list is asserted rather than trusted — that list is their claim about their own experiment. Measured, and three of their four criteria fail. DARVO arm rate is still 0 under greedy; ATTACK selection does not rise and falls for the rank-75 policy; group success collapses from 165/190/200 to 0 at 3/4/6 seats. The mechanism is not the assumed one: greedy answers the pressure by regulating, Stress plateaus at 3, so it never reaches the gate at 4 or the arm at 5 — H1-A acts as a solve-rate tax and H1-B is unreachable under competent play. A harness defect was caught before the claim: sweep discarded refused games silently and never reported its count, so "nobody won" and "nothing played" printed identically. Reporting H1 as unwinnable on that basis would have been the ADR-0018 family aimed at another repo's design. All 200 games ran in every cell; the zeros are real. Chaos d8 = 8 — the window's first override, redrew L against a structural L, so it changed nothing. Window 3 recorded in ChaosRollHistory. NOT REVIEWED: tier L owes a separate-agent adversarial review, and no H1 result may reach ground-game until it has run. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
|||
| 627992bc85 |
CB-WP-0037 done: T03 classification and T04 evidence
Some checks failed
ci / check (push) Failing after 5s
Reading Player_Mats.csv and Glossary.csv — which O4 had forbidden declaring about until they were read — found a rule. Player_Mats' choice_rule column IS GR-R03: at Stress 4-5 choose ATTACK or GROUND unless you spend a ready Freedom token. The engine's stress_gated and allowed_under_stress_gate match it exactly, and now have a tripwire. So Ornamentation.md gains §1.3: the unit is a column, not a file. Classifying Player_Mats as ornamentation would have thrown a rule away with the colour swatches. A mixed artifact is normal — a player mat is a rule printed on a decorated card in the box too. O4 is rewritten and re-grounded from provisional to rule accordingly. O5, O6, O7 declared with falsifiers. O7's is not theoretical: back_design_id is unread in four vendored files, and hidden information is what card backs are for. CB-EV-0029 answers T04's question per rule rather than as a count — yes, every checkable clause — and states the reading that result does NOT support: it shows GroundRules.md was a faithful secondary source for the clauses with behaviour to check, not that the engine is correct. 10 of 19 files vendored. Nine still unread, and Rules_Text.csv is the one that matters: every clause checked here was checked against our own transcription of it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
|||
| 53109ec5e5 |
CB-WP-0037 T02: the engine's rules against the edition's
Some checks failed
ci / check (push) Failing after 3s
Vendored DARVO.csv, Relations.csv and Scenarios.csv — the three unread files that carry mechanism. The engine has implemented the DARVO sequence and relation formation/breaking from GroundRules.md since the beginning, and had never read the game owner's statement of them. Every checkable clause agrees, and agreement is recorded rather than noted: a survey that finds nothing and leaves no trace cannot be told from one never run. The two hardest clauses to notice were already right — Focus placed "even if the Attack was cancelled", and Focus removed when the sequence ends before REVERSE. The tests are tripwires, not derivations. The match was made by a person reading prose, and that reading goes stale in silence when the prose changes; each behaviour pins the phrase it was read from, so a reworded edition goes red and asks for a human. Mutation-proven by rewording the cancelled-Attack clause. F25 raised, and it is the real yield: Scenarios.csv carries threshold_2_players/3_4/5_6, starting_stress and round_track, and the engine hardcodes all three — a match returning 5/7/9, stress: 2 at setup, five rounds. They agree on all four scenarios. These are the most contested numbers in the project; the whole 4/6/9 vs 5/7/9 episode turned on them, and the engine has been right by maintenance coincidence rather than by reading the file that owns them. Also pinned: Problems.csv and Scenarios.csv both state the deal and the engine reads only the first. They agree; nothing was checking. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
|||
| e5b805c185 |
CB-WP-0037 T01: F18 gets a reproduction, and F24 falls out of it
Some checks failed
ci / check (push) Failing after 4s
F18 was the only open finding clay-borg owns, the only register row lacking a reproduction, and the only off-target metric. It is also understated: it reads as display data, but among the 14 unvendored files are DARVO.csv (mandatory_effect, advance), Relations.csv (formation, breaking) and Scenarios.csv — rules the engine already implements from a secondary source and has never checked against the primary one. The reproduction records column reads AT THE ACCESSOR rather than counting them from the source: a list beside the code would be a second copy of a fact the get calls already carry, and grepping would over-count because six column names are shared between vendored files. The first version was wrong in this repo's signature way — it watched Table::at only, so it called visibility, required_solution and point_value unread when the engine reads all three through problems_of's own index lookups. Correct about the accessor, wrong about the engine: the ADR-0018 family, committed inside the artifact built to measure it. Problems.csv went 7/13 to 10/13 once the manual reader was recorded too. F24 raised: solution_deck() is a Rust literal that never opens Solutions.csv. It agrees today, which is the point — the engine is right by maintenance coincidence rather than by reading. Role `default`, with a test that goes red the moment either side moves. open, lacking a reproduction: 1 -> 0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
|||
| bd9e168af5 |
CB-WP-0036 done: the pace flag and the first ornament declarations
Some checks failed
ci / check (push) Failing after 4s
--pace speed|interactive, defaulting to Speed. Nothing reads it yet, and that is the point: it is the seam clay-animate attaches to, and a seam is cheap now where a retrofit would not be. A misspelt pace is refused rather than defaulting, because quietly falling back to Speed would look exactly like the renderer being broken. I3 is asserted rather than intended: the same scripted game at both paces must produce a byte-identical serialised recording and the same end state hash. Mutation-proven — leak the pace into the seed and it fails with "the recording differs by pace, so a renderer has become mechanism". specs/OrnamentRegister.md carries four declarations. This reverses the reasoning written in T03 earlier, which said the first declarations would come from F18's unvendored files: instances already existed. Hand order is what prompted the category, and "who deals" was the maintainer's own example. O3 is the interesting one — seat ORDER is mechanism because GR-R08 rotates Lead, while where a seat is drawn is not. I5 is executable: check_ornament_falsifier fails any row still declared that names no falsifier, mutation-proven red on O1. Presence, never adequacy, and the finding text says so. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
|||
| 31ae160043 |
specs/Ornamentation.md: what a game is besides its rules
Some checks failed
ci / check (push) Failing after 4s
Draws one boundary — between what the rules can see and everything else a player experiences — and says which repository each belongs to as the simulator grows. "Ritual" becomes ornamentation: half the category is material rather than ceremonial, and "decoration" is already spoken for in this repo (a control that cannot fail). The test is not "does it have a decision in it" — choosing who deals is a decision and is ornamental. The test is whether the state hash moves, which reuses the instrument that already binds a trial note to a position. The part that earns its place in clay-borg rather than in a renderer's stylesheet: calling something ornamentation is a CLAIM THAT IT DOES NOT MATTER, and this project's register is a list of times that claim was wrong — quantity in Tokens.csv, F18's four unread files, SOLVE offered where it could not act. So a declaration carries a falsifier, and "provisional" is a state it must say out loud. Downstream may read, may not decide — ADR-0007 D5 restated at the repository boundary. The port to clay-animate is deliberately NOT designed: no consumer exists, and an interface built against an imagined client is the same defect as a gate that cannot go red. Five invariants, four checkable today. I3 — same seed and decisions produce a byte-identical recording at any pace through any renderer — is the falsifier for the whole split. CB-WP-0036 re-declared from L to M accordingly: the animation architecture that made it L has moved to clay-animate. No code had been written and the tier-L review had not been run, which is the only reason it could be re-scoped rather than unwound. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
|||
| d7279483f6 |
CB-WP-0030: a control for the wrong-subject family
Some checks failed
ci / check (push) Failing after 4s
Seven claims in this project have been wrong the same way — the arithmetic right, the subject wrong. Four reached a document or another repo. ADR-0018 states the rule: a measured claim names the variable it depends on and shows the measurement moving with it. GameDesign §1.4 adds it as a fourth admissibility clause; the existing three are untouched. Honest yield is 3 clear + 1 partial of 7. It misses a count never made and a claim that is not a number, and D3 names those so nobody stops looking. The tempting fix — closing facts-check's 62 untagged literals — would have caught 1 of 7 and is deferred as separate work rather than bundled. loop-lint gains check_sensitivity_stated over arithmetic register rows, mutation-proven red on F17 and green when restored, with four self-test controls. It checks presence, never adequacy, and says so in its output. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
|||
| a9978c7a91 |
ADR-0017: window 2's verdict — the mechanism worked, my account of it did
Some checks failed
ci / check (push) Failing after 4s
not Tier M (changes how the loop constrains its own operation), declared at d8 because the rate for window 3 is what this document decides and declaring at a rate it invents would be circular. chaos d8 = 7, no override. I CLAIMED WINDOW 2 PRODUCED ZERO OVERRIDES, FIVE TIMES, AND IT IS FALSE. Declaration 3 (CB-WP-0020) rolled d8 = 8, overrode, drew S against a structural S, and changed nothing -- and CB-WP-0020 recorded it correctly at the time, in those words: "the first override at d8... It changed nothing... One." Counting the workplans takes one command and I never ran it. CB-EV-0024 asserted "zero" without checking; CB-EV-0025, 0026, 0027 and CB-WP-0029 each cited the one before. A claim propagated five times by citation rather than by measurement, in files whose subject was that exact failure. facts-check catches a copied number that disagrees with its source; nothing catches a number with NO source, asserted once and repeated. Registered F23, and all four evidence files carry an in-place correction rather than a silent edit (ADR-0012 D5). THE ACTUAL VERDICT: THE RATE IS WORKING. Eleven rolls at d8 -- declaration 1 opened the window at the old d4 -- against 1.375 eights expected, 1 observed. Not a shortage of evidence; the design. BUT THE RETIREMENT CONDITION GENUINELY CANNOT FIRE, and that took computing to see. "An override changes nothing twice running" needs a consecutive pair at P=1/3 each, so ~12 overrides expected, at ~1.4 per window: ~9 windows, roughly 100 declarations. A gate that cannot cash out on any realistic horizon is decoration, which ADR-0006 D3 forbids. Restated to be evaluated PER WINDOW: retire if a full window's overrides all change nothing, met in two consecutive windows. A window with no overrides is inconclusive and advances nothing. ~24 declarations rather than ~100. Window 2 counts as the first; window 3 opens at d8 and decides. Recorded and deliberately not acted on: declarations 5-9 rolled six five times running, ~1 in 370 for some run of five in eleven rolls. shuf tested over 200 rapid successive calls looks uniform, longest run three. Found post hoc, which is how coincidences become findings, so it is logged for a future window to check rather than treated as evidence. InnerLoop.md then crossed the loadability limit, and so did InnerLoopReference.md. The window log moved to specs/ChaosRollHistory.md: it grows by one entry per window, and a log inside a reference eventually crowds out the reference. make all: exit 0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
|||
| 302fc95c97 |
GR-E03 and GR-E04 played to the end — F14 closed, and the reason they were
Some checks failed
ci / check (push) Failing after 4s
unplayed was ours Tier S (a fix and a measurement inside a boundary; chaos d8=4 from CB-WP-0029's roll, no override). cb-play built EVERY game with ScoringMode::SharedGround and passed an empty patch. The mode was settable in scenarios and not from the driver, so two of the three shipped modes were unreachable from the only way anyone actually plays. F14 sat open for a week because nobody could reach the thing it was about. --mode added. All three now play out and give DIFFERENT WINNERS FROM IDENTICAL PLAY: shared -> all four seats (mastery 4), common -> P3 alone (top personal scorer), coalitions -> P1+P2 (best Bond network, 4>3>2). Same 37 commands, three answers. AND THEY ANSWER F17'S OPEN QUESTION. I had flagged that ATTACK might earn its place where Blame costs personal score. It does not, in any mode: SHARED GROUND 132/165/190/200 -> identical free but pointless COMMON PROBLEM 59/52/48/44 -> 59/52/48/34 a cost at six seats BONDED COALITIONS 131/134/132/116 -> 59/52/48/34 roughly halved The coalitions row has a mechanism and the data confirms it unprompted. GR-A07 flips a Bond to a Rivalry on Attack, and GR-E04 scores Bond NETWORKS -- so attacking destroys the thing that scores. And the attacking numbers in E04 are IDENTICAL to E03's, which is exactly what that predicts: break every Bond and each seat is a coalition of one, so GR-E04 degenerates into GR-E03. That check was not designed; it fell out. F14 -> applied. F17 strengthened and no longer bounded to co-op: ATTACK has no mode in which it helps, and one where it actively destroys your score. Still framed as a question rather than a verdict. DARVO is the pattern the game is about not falling into, so a self-destructive ATTACK may be the design. What ground-game has to decide is whether the namesake mechanic being unreachable in competent play -- in all three modes -- is intended. make all: exit 0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
|||
| f4eeddd726 |
25 test games, no faults — and F17 gets the artifact that changes what it
Some checks failed
ci / check (push) Failing after 4s
says Five games per seat count, 2-6 players. NO ANOMALIES: every game reaches 5 rounds with an outcome, no stalls, no stress above the cap, no over-claimed Problems. But the series showed something a crash never would. DARVO NEVER FIRED IN 25 GAMES and stress never exceeded 2. Measured wider: GreedyPolicy plays ATTACK exactly ZERO times in 10,000 selections across 500 games. THAT NUMBER IS ABOUT OUR BOT, NOT THE GAME. bot.rs ranks `Action::Attack => 10`, below everything. Reporting "the game gives no incentive to attack" from a policy we programmed to rank attack last would have been CB-WP-0025's C4 error committed again -- a single policy's behaviour presented as the game's. So the artifact varies exactly one number: ATTACK's rank in an otherwise identical policy, 200 games per cell. rank 10 (below all): 132/165/190/200/200 wins, 0 attacks, 0 DARVO rank 75 (above SUPPORT): 132/165/190/200/200 wins, 315-923, 13-218 rank 95 (above SOLVE): 0/0/0/0/0 wins, 1400-5170, 400-1000 THE MIDDLE ROW IS THE FINDING. Identical win counts at every seat count, while attacking hundreds of times and arming DARVO repeatedly. Attacking is not punished -- it is INERT with respect to the goal. Group success is a function of SOLVE alone, and ATTACK costs anything only when it ranks above SOLVE and displaces it. The maintainer was right and the reason is sharper than his phrasing: there is no incentive because there is no PATH. ATTACK's effects (Stress, Rivalry, DARVO) feed nothing that decides group_success. Bounded honestly to SHARED GROUND. Blame costs PERSONAL score, so ATTACK may earn its place in GR-E03 and GR-E04 -- which have never been played to the end (F14), and that is where to ask next. And this is NOT a claim the game is broken: DARVO is the pattern the game is about not falling into, so a self-destructive ATTACK may be the design. The question for ground-game is whether the namesake mechanic being unreachable in competent co-op play is intended. F17 promoted from note to raised, with games/ground/examples/attack-value.rs as its reproduction. Register: 18 findings, 8 with a resolving reproduction. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
|||
| 631fb41fc2 |
CB-WP-0029 T01-T03: components you can count, and a supply that does not bind
ADR-0016, Tokens.csv vendored, tracks and discs on the table, and a supply audit that found nothing and says so. T03 MEASURED BEFORE T01 DECIDED. 750 games, 2-6 seats, greedy and random: Protection reaches 1 per seat and 2 on the table against a supply of 6; Denied 3 of 5; relation links EXACTLY 12 OF 12 and never more; Focus/Blame 0 conflicts. The link row is the interesting one -- GR-L01's two-slot rule IS the twelve-token supply written twice, which is the shape of a supply needing no separate enforcement. AND THE FIRST VERSION OF THE FOCUS/BLAME CHECK WAS WRONG. It compared a seat's own placed Focus against its OWN blame_from -- but that list holds OTHER players' discs, so they are different tokens. It reported 2 conflicts; corrected, it reports 0. Fifth instance of this project's recurring defect, a number computed correctly about the wrong subject, and the first caught before it left the repo rather than by a reviewer. D2: a token is a VIEW, not a type. The aggregate gains no `Token` -- adding one would create a second source of truth for Stress, and the first time they disagreed the bug would be invisible because both would look internally consistent. D3: quantity does NOT bind, and the reason is not the measurement. A component limit the rules do not state is not a rule. Refusing a seventh Protection token would enforce something nobody ruled -- CB-WP-0023's error inverted: SOLVE was OFFERED where it could not act; this would REFUSE where the rules allow. The check ships as a standing control, so a future violation becomes a question for ground-game (does the box bound the game, or do the rules?) rather than a bound the engine invented. Registered as F22, withdrawn: a stated negative, because a survey that finds nothing and leaves no trace cannot be told from one never run. D4: Stress on a 0-5 track that turns red at 5 where DARVO arms, DARVO on OFF/DENY/ATTACK/REVERSE, Freedom as the two-sided disc the edition says it is, Protection and Blame counted, Lead and Round on the table. Two tests broke on token discs and both were FIXTURE defects: seat_centres matched every <circle> and track stops are circles. Seats now carry class="seat". The table height limit went 460 -> 500 as a CORRECTION, not a concession. 460 had no derivation; 500 does -- ~800px viewport less ~120 header and ~150 controls leaves ~530, and the version that broke dragging was 620. CB-WP-0021 T06's rule is to fix the measurement rather than lower the floor, and an underived number is a measurement defect. make all: exit 0. 66 render tests, 26 cb-play. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
|||
| b12725566b |
fix: a click target wearing a drag affordance made the controls look dead
Some checks failed
ci / check (push) Failing after 4s
Tier S (a fix inside a boundary; chaos d8=7 from the previous roll stands
for this continuation). Two observations from play that are ONE defect.
`play again`, `end session`, `pass` and the move buttons carried `.pick`,
which is cursor:grab. The stylesheet has .btn{cursor:pointer} BEFORE
.pick{cursor:grab}, so grab won.
A GRAB CURSOR INVITES A DRAG. A drag released over nothing posts nothing,
so the player picked up the button, let go, and the page did nothing. It
looked dead because the affordance told them to do the one thing that does
not work. Reported as two separate things -- "the button shows a hand to
pick up that it probably shouldn't" and "I can't start another game or
stop the server" -- and the first causes the second.
The click path itself was never broken: driving again->again and
done->done through the JS harness posts correctly. The logic was fine and
the invitation was wrong.
Click targets now carry `.tap` -- pointer cursor, same press affordance.
This extends CB-WP-0017's rule (interactive and inert must not look
identical) to: click and drag must not look identical either. The test
asserts both directions, because checking only that buttons lost `.pick`
would pass for a page with no affordances at all.
Registered F20 (applied) and F21.
F21 IS THE ONE I COULD NOT REPRODUCE: dragging did not work until after
the first note was saved. Ruled out the plausible mechanisms -- the
gesture logic posts correctly against the served page, the drag ghost
carries pointer-events:none so it cannot intercept the drop, and the
markup is identical before and after since the 303 re-renders the same
page from the same state. Remaining candidates are a <details> toggle
shifting layout mid-drag, a first-load timing difference, or browser-level
pointer capture. Reproducing it needs a browser, which no test here has --
the same gap F19 named. Recorded as unreproduced rather than given a
speculative fix.
And the fourth observation is confirmation, not a bug: "drawing my cards
from the deck is not implemented, I did not need to do that" is exactly
what CB-WP-0028 T04 determined and deliberately did not build. It is the
first evidence that importing the card text closed the comprehension gap
that produced the earlier click-the-deck request.
make all: exit 0. 62 render tests, 26 cb-play.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
|||
| a6e7acd4cf |
Register F19: the engine shipped a table nobody could play on
Some checks failed
ci / check (push) Failing after 3s
CB-WP-0028's overhead view was 620px tall, so the action cards sat a screen below the Problems and dragging between them was physically impossible. Seats were drawn inside the table; the `table` drop target was a card among the buttons rather than the drawn surface. make all passed throughout. Every test asserted the DOM was correct -- which it was -- and the JS harness posts a correct gesture against a page a human cannot drag on. Kind `degenerate`: it fires and collapses play. State `applied`: fixed the same day, with height, seat-position and single-drop-zone proxies added. They are PROXIES -- nothing here lays out a browser, and the gap CB-EV-0026 named a day earlier is unclosed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
|||
| 02402c36b2 |
CB-WP-0028 declared, and two findings from play registered
Some checks failed
ci / check (push) Has been cancelled
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> |
|||
| 7ed9fc730a |
CB-WP-0025 T06/T07: a difficulty baseline that reports its own confound
Some checks failed
ci / check (push) Has been cancelled
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> |
|||
| 81e0aba59a |
CB-WP-0025 T05: the search works, and it falsified this pass's own
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> |
|||
| b27aa14df0 |
CB-WP-0025 T04: specs/RetrospectiveAnalysis.md, and a benchmark that
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> |
|||
| 8d58568013 |
CB-WP-0024: the table you can watch
Some checks failed
ci / check (push) Has been cancelled
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>
|
|||
| 6be9fbc9af |
CB-WP-0026: collect the rulings -- ten answers that arrived and were never applied
Some checks failed
ci / check (push) Failing after 3s
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> |
|||
| 561facce43 |
CB-WP-0022 T05/T06/T07: the register, and what its first run found
Some checks failed
ci / check (push) Has been cancelled
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
|
|||
| b4f51effad |
CB-WP-0022 T04: specs/GameDesign.md -- what a reproduction must show
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>
|
|||
| 6487d33f27 |
CB-WP-0023: SOLVE is legal only where it can do something
Some checks failed
ci / check (push) Failing after 4s
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> |
|||
| 69c1658d20 |
CB-WP-0019 T03/T04: the cost rule written down, and the lifecycle
Some checks failed
ci / check (push) Has been cancelled
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> |
|||
| 0b6f7c5bc8 |
CB-WP-0019 T01/T02: AM-4b asks what a contributor acquires
Some checks failed
ci / check (push) Failing after 4s
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> |
|||
| cc8917a6fb |
CB-WP-0019-T05: what the meta budget is for, at 80/20
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> |
|||
| a733826d95 |
CB-WP-0018 T03/T04: explanations, and window 1's verdict
Some checks failed
ci / check (push) Failing after 3s
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> |
|||
| ee37b82675 |
CB-WP-0015: the two inert clauses, AM-7 scaling and AM-8 N=10
Some checks failed
ci / check (push) Failing after 3s
Provenance (tier S, one paragraph in lieu of survey and ADR): the two clauses mutation-check has reported inert since CB-WP-0005. AM-7's scaling ratio was held up by a test literally named replay_100k_events_is_linear_and_fast that computed both throughputs, printed both, and never divided one by the other. AM-8's N=10 was held up by a runner that does two. Both are now red. AM-7 3/3, AM-8 2/2, M-D1-MUT 10/14, and ADR-0005's >=10-of-14 prediction MET for the first time. Neither was closed by amending the question away, which was the live risk: the denominator is unchanged and the four unenforced rows are the four already unenforceable. AM-7 needed three estimators. Best-of-N per leg then divide (AM-6's, correct for a floor on one number) gave 0.581-1.085 on an unchanged binary; legs back-to-back gave medians 0.931-1.004; legs interleaved at fold granularity give 0.987/0.991/0.989, and 0.989 under 8-way CPU contention while absolute throughput fell 4x. The INDETERMINATE guard demanded unanimity and failed a good measurement over one sample 0.001 under the floor; it now requires a two-thirds majority. The control that matters: AM-6's constant-cost mutation halves throughput and leaves this ratio at 0.999x green, so AM-7 is not a second AM-6. AM-8 kept N=10 because the measurement said so. Perturbing the RNG only from its fourth construction on: --runs 2 PASSES, --runs 10 fails. A late-onset divergence is deterministic, not flaky, so it is a control rather than a coin flip. Ten runs live on one scenario (make am8, ~2s) rather than all 25 (47s a build). GameKernel 5b records it. The full run also found AM-4a's own mutation stale since ADR-0008 D3 moved the target 250,000 -> 161,000 in CB-WP-0013 -- reported HARNESS-BROKEN, no score published. The build-free half of that check is now a --self-test assertion, so make all catches the next one. mutation-check clauses may now carry their own verify and mutation, and then the enforced flag is measured rather than declared; a declaration disagreeing with its measurement is refused. make all exits 0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
|||
| d2c3f340f9 |
CB-WP-0013-T02/T03: retire SH-3 as a gate; correct AM-4a and its target
ADR-0008, tier M (survey and ADR merged).
D1 — SH-3 retired as a gate, kept as a diagnostic. Investigating it
found a third defect, deeper than the two this pass was declared on.
Re-deriving batching from the raw transcripts, independently of cb-cost:
CB-WP-0011 pass 54 with tools 0 batched 0.0%
gap -> next decl 16 with tools 6 batched 37.5%
CB-WP-0012 pass 86 with tools 0 batched 0.0%
gap -> next decl 10 with tools 1 batched 10.0%
CB-WP-0013 so far 10 with tools 0 batched 0.0%
Zero batched turns in 150 in-pass responses; 37.5% in one gap, above the
20% floor. Batching needs two calls whose inputs are known at once —
orientation work. Implementation consumes each step's result before the
next. SH-3's window is since the last commit, which during a pass is
always implementation. The metric could not read above ~0% in the window
it was gated on. A floor the window structurally excludes is not a
target.
This pass's own declaration was also wrong: it claimed batching "has got
worse" (7.8-8.6% vs 1.1-6.3%). Differently-placed windows, not different
behaviour. Withdrawn — the same class of error, in the pass written to
correct it.
Not retargeting to match the measurement: the floor was not moved to 6%,
the gate was removed on an argument about what the quantity is worth.
The number is still reported; only the verdict is gone.
D2/D3 — AM-4a counts --edges normal,no-proc-macro: 157,202, not 246,250.
The target moves down with it, 250,000 -> 161,000, so the correction
hands back essentially nothing (headroom 3,750 -> 3,798). Three controls:
the exclusion drops exactly the five expected crates, only removes and
never adds, and is not a no-op.
The DFD gate then caught the follow-on it exists for — three historical
documents carrying live fact tags for a number that had changed. Not
rewritten; untagged, with a supersession banner.
AM-4b is deliberately not corrected: its proc-macro share is unmeasured.
gate-review now reads 0 due, 0 silent, 0 drifted — GATE-REVIEW earns its
first caught entry by forcing SH-3's re-justification, and the registry
has no silent gates left.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
|||
| 6080c4cf60 |
CB-WP-0013-T01: SH-3 refuses a window that cannot carry a rate
The metric six evidence files reported as 0.0% was never measured. --shape-budget windows since the last commit, and it is read while writing the evidence file — right after a commit, when the window holds one or two responses. SH-1/SH-2 are location statistics and survive n=2. SH-3 is a rate: at n=2 its only possible values are 0%, 50%, 100%. cb-cost.py gains sh3_line(), which below a minimum sample prints "insufficient sample" and no verdict. The floor is derived: if the true rate were exactly the 20% target, P(zero batched in n) = 0.8^n, and at n=14 that is 4.4% — so "0 batched in 14" rules out a target-meeting rate at ~95%. Below that the tool has nothing to say and now says so. The window was kept rather than split. SH-3 could have been given a per-pass window, but the budget's purpose is the open remainder since the last commit, and giving one of three metrics a different window makes "the window" ambiguous in a tool three specs cite. Four controls, three mutations, each red for its stated reason — including the one the evidence files actually hit, where a refusal is printed as a measured zero. SessionShape.md §4 carries the correction with the real per-pass figures (1.1%-6.3%), beside the eighth trusted-arithmetic instance. This is the ninth, and the second in this same metric. It also shows what the frozen 0.0% hid: against the pinned 7.8%-8.6%, batching has got worse, and six passes reported a breach that was moving underneath them. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
|||
| 2b6bf29e8f |
CB-WP-0009-T03: InnerLoop v1.6
D2 the two exemptions — repairing the instrument that reports a breach is always in budget, and the maintainer may authorize above-line work in the workplan frontmatter. v1.5 had neither, and the first thing it did was forbid fixing the budget's own defect. D4 loop work cashes out into something runnable in the pass that invents it, with the measured basis and the refutation condition stated. D5 the tier table now triggers at M for changes to the loop's own operation, closing the gap CB-RES-0005 §6 opened and this pass's own ADR had to declare around. The file went from 399 lines to 386: the chaos-roll calibration rationale and the v1.0-v1.3 change log moved to InnerLoopReference.md. Loadability is a gate too, and growing the file to fit a rule about gates would have been the joke writing itself. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
|||
| b79ea9690d |
CB-WP-0007 T01+T03: window the metric, budget it, cap meta at 25%
Scope cut first, on the maintainer's decision after a spend review: the project is 38% product / 62% loop-meta, cost per response is 2.9x worse than its best window, and INTENT stage 0 still lacks a CLI player and bots. CB-WP-0005 and CB-WP-0006 cost ~$74 — 31% of all spend — for zero measured efficiency gain. T02 and T04 are cancelled unstarted. T01: SH-1/SH-2/SH-3 now report over the window since the last commit, and the cumulative figure is retained but labelled "history, NOT the metric". The prediction held decisively — window 655,744 mean context against cumulative 255,307, a 2.6x gap against a 20% refutation threshold. A cumulative mean over 1,094 responses cannot detect a worsening trend because the history outvotes the present. T03: `make shape-budget`, modelled on CB-01/CB-02. Soft thresholds are the existing SessionShape targets; hard is 1.5x, set before the next measurement per §Step 4. Deliberately not in `make all` — failing the build on context would block committing, and committing is what closes the attribution window and is the natural point to compact, so a gate that blocks the remedy is a trap. It fires HARD on its first run: 656,574 against a 300,000 ceiling. InnerLoop v1.5 establishes the soft 25% meta budget. Workplans declare kind: product|meta|mixed and `make status` reports the share; mixed splits 50/50 and says so. Soft on purpose — a task already started may be finished, because stopping mid-task to satisfy a ratio wastes the work. What it forbids is opening new meta work above the line. A pass that exceeds it must say so in its evidence and name the product work displaced. First reading: 68% OVER, of $74.22 attributed. Product reads $0.00 because the only product workplan, CB-WP-0001, predates qualified task ids and its bare T## labels collide across passes — stated in the output rather than papered over. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
|||
| 327bda64ab |
CB-WP-0006 T07: implement K18, amend K14
Two rules, two different answers, which is the point of a task phrased "implement, or amend and say why". K18 is implemented. "Criterion benches driving the same scenario format at scale" was false — the bench hardcoded its commands and never touched ScenarioFile, while MetricsAndScenarios §3 pointed at a benchmarks/ directory containing only baselines/. benchmarks/synthetic-3p.yaml now holds the workload and both the bench and bench_shape read it: the workload is data, not code. A second defect surfaced while fixing the first. After the bench switched to the file, bench_shape still hardcoded the same sequence, so the workload existed twice — deleting end_round from the YAML broke bench-test while bench_shape kept passing. Duplicated-fact drift in executable form. Both now read the same include_str! and deleting a command breaks both. Explicitly not claimed: this does not unblock AM-3. AM-3's baseline is a declarative game object — moves, turn order, rules. synthetic-3p.yaml is a command list; the rules live in games/ground. Marking it as AM-3's subject would compare a script to a game definition, which is the category error AM-3 is blocked on. The file says so in its own header, where the next person will be tempted. K14 is amended. CommitWindow had zero non-test users and GROUND enforces the same contract inline. Wiring GROUND through it was rejected: it would change the serialized shape of `selections`, which four scenario files assert by dot-path and every state hash depends on, for the sole benefit of making a sentence literally true. The deciding argument is INTENT's, not convenience: abstractions are extracted from working games rather than invented in isolation, and no concept becomes canonical until it survives a second concrete use. CommitWindow was invented before any game needed it and has survived none. Imposing it on GROUND would manufacture the first use rather than discover it. So K14 states what is actually guaranteed, CommitWindow is marked provisional in the source, and it carries a delete-by date of 2026-12-31. Kernel spec->code link 16/18 -> 18/18, stated with the caveat the gate prints every run: that is about names, not assertions. Two self-tests broke and both broke correctly. rule-coverage's gate test hardcoded "unlinked rules exist today" and failed when the last one was linked; it now computes that and asserts the gate fails iff rules are unlinked. facts' text check rejected k_unlinked once it became legitimately empty; empty now renders as "(none)" and the check distinguishes absent from empty. M-D1-MUT: 8 of 14, unchanged — K14 and K18 are kernel rules, not acceptance rows. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
|||
| 1edadac9a2 |
CB-WP-0006 T06: K10 replay bundles, --replay, and AM-7 re-earned
INTENT design decision 8 of 10, unimplemented for six passes. cb-sim had no flag parsing at all, so --replay had nowhere to go. The bundle is manifest + commands.log + initial.snapshot + expected.yaml, dev-only behind the scenarios feature and charged to AM-4b. The command stream goes through the K11 framing built in T05, so a truncated bundle is detected rather than replayed short — the two tasks compose rather than duplicating. The reviewer's D2 correction was real: this was not "a directory of four files". Pass carried only the end state, RunOutcome::Failed was a formatted String, and scenario.rs created an EventLog, appended to it and never read it. All three had to change. The first round trip failed to reproduce, and the cause is worth keeping: state_hash_hex over a serde_json::Value is a different canonical form than over the typed aggregate — Value's map is key-sorted, a struct serializes in declaration order. The bundle was written with one basis and verified with the other. A round trip written to recompute its own comparison value would have PASSED this bug; it failed because the recorded hash came from the producing process, which is control 2's entire purpose. make replay-test implements ADR-0005 §6's four controls, 14/14: a committed deliberately-failing fixture outside the corpus with covers: [] so it neither fails `make sim` nor inflates AM-1; a tampered recorded hash must fail; a log short by one byte and a corrupted length prefix must be rejected; and a mutated manifest seed must fail — which bites only because replay re-derives the initial state from seed+setup and checks it against the recorded snapshot, since restoring from the snapshot alone would leave the seed inert. Plus a control on the controls: the bundle must still replay after every mutation is reverted. AM-7's hash-identical clause is re-earned. The probe records a hash per per-game segment and replays each from its own genesis; folding from the wrong seed now fails. That is the clause ADR-0005 §4 withdrew as mutation-proven inert. The scaling >= 0.9x clause is still unenforced, so AM-7 stays PARTIAL — reported, not rounded up. Kernel coverage 15/18 -> 16/18. facts-check immediately caught the spec's copy of that number going stale, on a number that moved the same hour. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
|||
| 98c6cd24c3 |
CB-WP-0006 T05: K9's assertion, K11's format, and the AM-11 suites
K11 is implemented: crates/cb-events/src/store.rs, magic + version header, 4-byte little-endian length prefix, append-only. Reimplemented not assimilated per ADR-0005 §2 — no new dependency, and AM-4a/AM-4b are unchanged at 246,250 / 317,021 because nothing entered the graph. The operative clause is "detected", so corruption is tested rather than assumed: a tail short by one byte, a half-written length prefix, a length prefix corrupted to claim more than the file holds, foreign magic, and a future format version are each rejected with a distinct error. A reader that accepts a truncated tail is worse than no format, because it silently returns a short history that looks complete. AM-11 is earned. LogStore has two impls — MemLogStore and FileLogStore — driven through ONE conformance(). The trait carries raw/set_raw precisely so the corruption controls live in the shared suite: a format contract that only one impl enforces is not a contract. The same shape is retro-fitted to KernelRng, which is what AM-11 actually names: ChaChaRng and NullRng now pass one suite asserting bounds, draw(1) == 0, determinism across fresh instances, and shuffle preserving the multiset. They were previously exercised by two separate tests, which is why "met, narrow" was never earned and ADR-0005 §4 downgraded it. K9 gets the assertion it did not have: snapshot at seq N + events N+1..M must equal the from-genesis fold, hash-compared, on GroundState, single-seed on purpose — AM-7's probe folds a multi-seed log, which is not a replay of anything, and that defect is not repeated. Two positive controls: the log must exceed 50 events, and the mid-log snapshot must differ from the end state or "apply the remainder" is vacuous. Proof it works: the exact mutation that SURVIVED in CB-WP-0005 — making Snapshot::take discard its EventSeq — now fails on the K9 assertion. AM-11's mutation breaks NullRng::draw to return its bound and the shared suite fails. That is what M-D4-SWAP claims — either impl substitutable — and exactly what two separate per-impl tests could never demonstrate. M-D1-MUT: 7 -> 8 of 14. CB-EV-0001's scoreboard is refreshed: AM-2, AM-5 and AM-9 added, AM-6 moved to enforced, and the headline total corrected from 4 to 8 — it had gone stale inside the same workplan that produced it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
|||
| db6445ae37 |
CB-WP-0006 T04: withdraw AM-4c; and fix where AM-6 is measured
AM-4c is withdrawn from the acceptance table and retained as a reported diagnostic. GameKernel §5a carries the argument. The ratio has no monotone better direction. INTENT's rule is "own the semantics, assimilate the implementation": rising can mean owning semantics properly or reimplementing what should have been assimilated; falling can mean leverage or dependency bloat. A target requires knowing which way is better. It is also redundant — AM-4a/AM-4b bound the denominator and AM-2 bounds own-source density, so AM-4c is a ratio of two already-targeted quantities. Measured at withdrawal: 1,426 own lines per 100k third-party (shipped), 1,107 (dev). make dep-weight now prints both, labelled diagnostic — the row was never actually reported before. M-D1-MUT keeps AM-4c in its denominator on purpose and says so in the output. Dropping it would move the score 7/14 -> 7/13 without enforcing anything: a score improved by deleting the question. Decided before Phase B deliberately, since ADR-0005 predicts own-source growth that will move this ratio; deciding after would be the retarget §Step 4 forbids. A T01 correction found here. The AM-6 gate failed inside `make all` at 38,753 ev/s against 341,280 in isolation — a 9x drop, because cargo test runs binaries and threads concurrently. A throughput assertion inside a parallel harness measures contention, not throughput. T01's measurement was valid; its gate placement was not. Fixed by running it only where valid — #[ignore] plus `make am6` in release with --test-threads=1, now 2.0M ev/s at 20.2x headroom — and not by lowering the target, which T01 forbade. My first attempt did drift that way, adding a debug "sanity floor" of 50,000, and was backed out: a second threshold is still a second chance to tune. The mutation then went SURVIVED on the first run after the move. 4,000 black_box iterations were calibrated against debug's 3.4x headroom and are invisible against release's 20x. Raised to 100,000; back to red. A weak mutation is not a fixed property of a row — it can become weak when the row's measurement conditions change. Tier S (amends one row, creates no capability), chaos d4=2, no override. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
|||
| fd19f4e878 |
CB-WP-0005 T07/T08: control loop, retrospective, InnerLoop v1.4
T07 — CB-EV-0004. 70 responses, $16.03. Test 1 MET: 1 spec -> 2, 58 rules -> 76, 1 source file -> 10, and the new denominator came in at 83% naming K10/K14/K18. The stated failure mode — a widened denominator reporting the same percentage — did not occur. Test 2 UNMET: M-D1-MUT 4 of 14 against >=10, and wrong about what as well as how much. The diagnosis was three absent kernel rules; the measurement found eight rows with no instrument at all. Test 3: quality held, and widening surfaced far more than the seven known defects — six further uninstrumented rows, HDN #7 (rule-coverage's self-test green while the tool was broken), a stale $248.46 invisible to facts-check because it was untagged, and a fifth error class. The clean test CB-WP-0004 was owed is now run, on a pass that used the tools without building them. The two categories whose tools removed the manual path are at 0 turns two passes on; the two that merely offered a better option are now the entire mechanical cost of a pass. Absolute mechanical cost fell $51.76 -> $6.13. The mechanism holds. Reported because nothing else would: SH-3 batching is 0.0% this pass — 67 tool calls across 67 responses — against a 20% target, and mean context 315,170 against 200,000. SessionShape has stated these since CB-WP-0003 and none has ever been enforced. T08 — the retrospective answers its question: yes, a weak mutation is the new grep, and it is worse, because it fails in the opposite direction. mutation-check's first run produced two SURVIVED verdicts and both were the author's own no-op mutations. The fifth error class: false accusation. HDN, TA, SSB and DFD all under-report — a real problem passes. FA over-reports: it publishes the claim that working code is broken, sends the next pass to fix something that is not broken, and is more credible than the truth because it arrives with a measurement attached. Thirteen instances, five classes, six passes, and the newest class is one that hardening created. One correction to CB-WP-0004 T06: "a gate only pays if it removes the manual path" is a predictor of whether a gate saves money, not a criterion for whether it is worth having. mutation-check fails that test and produced the most valuable findings of the pass. InnerLoop v1.4: where a claim rests on numbers, the adversarial reviewer must read the assertion behind each quoted number and mutate it. Re-running the command that prints a number is not verification of that number. Second verification step to inherit the author's blindness; both fixes replace re-derivation with adversarial execution. CB-WP-0005 status -> done, 5 of 8 tasks, 3 cancelled into CB-WP-0006. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
|||
| 145611e3b6 |
CB-WP-0005 T03: correct the record, and defer Phase C
Four verdicts in evidence/CB-EV-0001 corrected in place with a dated note, per ADR-0005 §4: AM-7 replay split (timing met, hash-identical withdrawn), AM-10 withdrawn as written and restated as AM-10' (the K6 determinism lint it actually measured), AM-11 downgraded to unmet, and AM-1b added to the scoreboard it was missing from. The scoreboard gains an Enforced column carrying M-D1-MUT, because a row can be measured and still enforce nothing and the table had no way to say so. AM-6 now reads "met, 16.5x" alongside "not enforced — nothing compares any number to 100,000". A fifth correction surfaced that ADR-0005 did not list: AM-12 still read $248.46, the figure CB-WP-0002 disproved and corrected to $93.15 four workplans ago. It was stale in the evidence file ever since — untagged, and therefore invisible to facts-check. Now tagged. A duplicated-fact instance that survived the gate built to catch duplicated facts, because that gate only checks copies that opted in. Recorded for T07. GameKernel §5 carries the AM-10 withdrawal and AM-11 downgrade inline so a reader of the spec cannot reach the old claim. Phase C is deferred before starting, per the stop condition T02 wrote and the maintainer's decision. It is scoped to five rules; the measurement says eight acceptance rows have no instrument at all. Building it as written would proceed on a diagnosis the instrument had just contradicted. T04-T06 stay in the file with their analysis intact and move to CB-WP-0006. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
|||
| bb35fcb168 |
CB-WP-0005 T01: spec->code link over every numbered spec and every crate
AGGREGATE becomes a list of source roots and rule patterns become
per-spec, so the link runs over every numbered spec x every crate rather
than GroundRules.md x games/ground/src/lib.rs.
The prediction held on the first run:
AM-1b kernel spec->code link: 15/18 (83%) across 10 source files
unlinked: K10 K14 K18
Kernel rules are link-only by design, and the output says so: they are
kernel invariants with no aggregate, setup preset or command vocabulary,
so scenarios/kernel/*.yaml with covers: [K11] would be a tag in a
directory the runner cannot dispatch. Claiming scenario coverage for them
is the inflation this gate exists to prevent.
Per ADR-0005 §5 the kernel arm reports without feeding the exit code
until 2026-08-31, then binds — the date in the tool, not in prose, with
days remaining printed every run, because open-ended "gate it later" is
how AM-4's targets went unratified for four workplans. The self-test
asserts the gate returns 0 before that date and 2 after.
The zero-rules positive control is replicated on the new denominator: a
kernel regex that stops matching aborts rather than printing 0/0 as
though it were 100%.
The self-test passed while the tool was completely broken. A print(
inside say() became say(), so every real `make coverage` died with
RecursionError while --self-test reported all-ok — it only ever called
kernel_arm(quiet=True) and never executed the reporting path. The control
named the behaviour and did not assert it, which is precisely what this
workplan is about. Fixed by exercising the loud path and asserting it
prints, then verified by re-breaking say() and confirming both new checks
go red. Seventh instance of the harness-does-nothing shape, in the tool
written to find that shape.
Also caught by its own gate: a self-test label that printed "0 K-ids"
beside a passing ">5" assertion, because the detail string rebuilt the
pattern with different escaping. A label that contradicts its own check
is worse than no label.
k_rules, k_linked and k_unlinked are registered facts under facts-check.
A limit of that checker is recorded rather than patched: it is
line-based, so a tagged value that prose-wraps fails.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|