What this engine enforces, and how that is known

This is a rules engine for a trading card game, written so that the claim "it enforces the rules" can be checked by somebody who does not trust it. Every number below is generated by the thing it describes, and the command that produces it is printed beside it. None is typed by hand.

1. What it enforces

Two reports, one per dimension. The rule report maps the rulebook's nodes to the tests that exercise them; a rule counts as covered only when a test cites it and genuinely exercises its content.

cargo test -p riftbound-conformance # writes docs/coverage.md; a test asserts the committed file matches

Read the rule report — every covered node, and every uncovered one.

The card report is the other direction: which cards the engine runs, and for the ones it does not, what was missing. This server is serving a pack right now, and these are its own numbers:

reading the pack…

cargo test -p riftbound-origins --test pack write_card_report -- --ignored # writes docs/cards.md; a test asserts the committed file matches

Read the card report — the refusals come first, because they are the more useful half.

2. What happens when it does not know

Every card is in exactly one of three buckets, and there is no fourth state and no default. A card the engine runs has a test that plays it. A card it cannot run is refused by name: a deck holding one will not start a game unless both players override, and an override puts a banner naming that card on screen for the whole game.

This is the stronger claim, and the one that survives contact with a rules expert. The failure this design exists to prevent is a card that silently does most of what it says. Partial is a lie here; there is no arm for it.

Each refusal names what was missing in the engine's own terms. The card report collates them: every refusal is filed under one named shape, and the shapes are ranked by how many cards want each. So the refusals are not a list of failures, they are a specification of what the engine lacks — which is the honest answer to "what would it take to finish this", and the part of this document a rules expert can argue with.

Each refusal is filed under the first shape its reason names, so a count there is a floor and never a ceiling. The report says so where the ranking is, rather than here.

3. Why believe the tests

Because each one has been shown to fail. Every card carries at least one entry in a mutation ledger: weaken the card — its cost, a printed number, a tag, a keyword, its program — and that card's own test must go red, while the tests naming other cards stay green. A mutation that reddens everything proves only that it compiles.

scripts/cardmut.py scripts/mutations/task-N.json # every mutation names the tests it must BREAK and those it must leave GREEN

This is not decoration. It has caught tests that passed for the wrong reason, a near miss that proved a different clause than it claimed, and a card characteristic that no test could observe at all.

Two accidents are worth reporting, because together they are the closest thing to a control this project has. On two separate occasions a group of cards was transcribed and bucketed twice over, by authors working from the same index who could not see each other's work: four cards the first time, surfacing when two branches were merged, and four more the second, where one branch was written from a commit that predated the other and was never merged at all.

All eight agreed on which bucket the card belongs in. In both accidents the refusals independently named the same missing shape in the engine, in the engine's own terms — not the same words, but the same absent mechanism, located in the same place in the code.

Eight is a sample and not a study. But bucketing is the judgement this whole document rests on, and this is the only evidence available that the judgement is reproducible rather than one author's taste.

4. Can a disagreement be settled

A game's record is its seed, the pack's hash, the engine build, and every answer given, in order. Replaying it reproduces the position exactly, and the record carries the fingerprint it reached so it can check itself. A record that is not the record it claims to be is refused rather than replayed into a different game and called faithful, and the suite has tried these ways of making one:

16 of them, each its own case in the suite:

cargo test -p riftbound-play --test plain -- record::write_tamper_list --ignored # rewrites that list above from the suite; a test asserts the page matches

The last one is not a tamper at all: a game still being played hands over a record with the parts that would rebuild it held back, because rebuilding it would rebuild the half neither player may see. The replay route has to refuse that too, and say so rather than fail over a missing field.

The interesting ones are the forgeries. A file edited in a text editor no longer implies its own digest and is refused by arithmetic, which is right and is also easy. A file edited and then made to add up again can only be caught by replaying it and comparing where it lands — which is what the fingerprint is for.

So a contested position is a file, not a story.

5. The licence

Three repositories with a firewall between them. Rules live in the engine and card data lives in the pack; this server and its client hold neither and know a card only by its identifier. Three scanners run over every tracked file of all three and must read zero: verbatim containment against the rulebook, ordered-subsequence echo against every rule sentence, and containment against the card index.

RIFTBOUND_REFS=~/riftbound-refs ./scripts/gate.sh

The material those scanners read is not in any repository and never will be.

What this does not claim

That the engine implements the whole game. It implements what the reports say it implements, and refuses the rest by name. Of the four verification layers this project specified, three are built: rule-cited tests, property and fuzz testing, and determinism. The fourth — a corpus of scenarios drawn from real judge rulings — is specified, has a harness, and is empty, because its content is somebody's judgement and inventing it would make it the one part of this project that is not evidence.