Commit graph

7 commits

Author SHA1 Message Date
8ae68195b8 CB-WP-0049 T04: a seat that attends to the modules in play
Some checks are pending
ci / check (push) Waiting to run
ModuleAwarePolicy reads the RESOLVED Rules -- one policy, not one per
module. H2AwarePolicy would have been the blob schema 2 exists to
retire, rebuilt a layer up; reading Rules means a two-module
configuration gets both terms and a future module is one arm here rather
than a new policy per combination.

Two terms, both reading the table: prefer the Problem whose Stress falls
on me (problem_stress.scoped), and treat ATTACK as a Stress tool at the
gate (attack_relief.self_soothe_ge4). stress_scope and the owner marker
are public regardless of the card's face -- the H2 rules place the
marker ON the card -- so it is blind by construction.

THE CONTROL I CLAIMED WAS REAL WAS VACUOUS, AND MUTATION SAID SO.
"Under the baseline the two must be identical" swept fresh deals across
36 combinations, and forcing the scope term to fire regardless of
configuration left it GREEN. At a fresh deal only the Surface Problem is
face up, so exactly one SOLVE is legal and no ranking term can move the
argmax. The control could not distinguish the property from its
negation.

Both tests now use a BUILT position -- two face-up, unclaimed, equally
valuable Problems differing only in scope -- under H2 for divergence and
under the baseline for the control. The mutation goes red there.

That is also a finding about the module: the scope term is INERT at
round-one positions, so anything measuring H2 with round-one-heavy play
is measuring a mechanism that has not started. Recorded, not tuned away.

Also: CB-WP-0048 was `active` with every task closed; loop-lint's
lifecycle rule caught it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-09 01:25:22 +02:00
48a7bce04d CB-WP-0048 T02/T03/T04: Configuration replaces Variant in the state
Some checks failed
ci / check (push) Has been cancelled
The three-armed enum could not express a configuration carrying two
modules. It does now: --variant h1 expands to problem_stress.flat_any_open
AND attack_relief.self_soothe_ge4, and scoped_plus_attack_soothe plays.

Legacy names alias forever via serde(alias="variant") plus a
scalar-or-map deserialiser. serde(default) alone would have been a silent
migration bug -- every H1/H2 recording would have come back as baseline.
All 26 scenarios pass unchanged; none pins a state hash.

Three things shipped broken first, all caught by gates rather than by
reading:

1. `profile` was in the state hash. with_config(select("ground-darvo-r0"))
   sets profile=Some("baseline") where setup alone leaves None, so two
   states at THE SAME POINT IN ASPECT SPACE hashed differently and a
   replay bundle stopped reproducing its own initial state. Now
   serde(skip): a hash covers what determines play. This was the open
   judgement from T01 and it did not survive contact with the replay path.

2. A YAML parse inside the event loop. rules() -> resolve() -> catalog()
   re-parsed catalog.yaml per rule check; AM-6 fell to 9,345 events/s
   against a 100,000 target. OnceLock, and aspect validation moved to
   where a configuration is BUILT.

   Then I nearly optimised a phantom: 470k still looked like a 3x
   regression against the "~1.7M on bnt-lap001" reference in the gate's
   own message. Making rules() free measured 491k -- this machine's
   ceiling. Before optimising against a reference, measure the ceiling
   with the suspect code removed.

3. The refusal did not fire on the path a player takes.
   `--module problem_deal.pressure_deck` played a full baseline game and
   reported success, because with_config is a builder and fell back to
   the printed rules -- the silent no-op ADR-0022 exists to refuse. Every
   unit test of resolve() passed. The helper was tested and the driver
   was not, which is CB-WP-0033's finding verbatim. The new test asserts
   refusal BY NAME and that no game was played.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-09 00:54:34 +02:00
98f600b1d3 Workplan status is active, not in_progress
Some checks failed
ci / check (push) Failing after 3s
The spec is explicit: a WORKPLAN is active|done|paused; in_progress is a
TASK status. I used the task vocabulary on the workplan frontmatter, and
the hub rejected both with a 422 on every sync.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-08 23:48:27 +02:00
036658ac76 CB-WP-0048 T01: record the pass in the workplan
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-08 22:30:28 +02:00
a87afca48f Sync hub state for CB-WP-0048
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-08 22:10:43 +02:00
75080beb03 CB-WP-0048: conform task headings to the parser's shape
Some checks are pending
ci / check (push) Waiting to run
status.py resolves `## Task: <text>` immediately above a task block;
`## Task T00:` resolved to nothing and the gate said so.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-08 22:09:58 +02:00
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>
2026-08-08 22:07:57 +02:00