Public: anyone can read this; the crew can change it.

No charge leaves by any door: one property test over many seeds, every viewer and every read #63

open not picked up yet opened this
opened this

Intent. The game is only a game while a charge stays secret, so prove it the way a property is proved — many dealt tables, every kind of viewer, every read the app has — instead of trusting that each door remembered.

src/actions.ts redacts in one place (seesCharge), which is right, and #49 plays RULES.md §10 once through three doors, which is also right. Neither is a guard against the next read: a route added later, a tool added by #13, a terminal screen added by #41 or a column added by a migration can each leak, and nothing currently fails when one does.

Done looks like

  • [ ] src/secret.test.ts (new): for many seeds (enough to cover the clause pool, fast enough to stay inside a couple of seconds), deal a table through the real startTable on a real database under a temporary FORGE_APP_DATA, then ask every read the app has as every kind of viewer — each seated player, a guest, a signed-in stranger with no seat, and an admin with no seat.
  • [ ] The reads are enumerated from the app, not by hand: every GET in routes that takes no unknown parameter, every read tool in mcp.ts's tools, and the terminal's screens once #41 has made them pure functions of state.
  • [ ] The oracle is the database, not a written list: read seat.charge_json and game.seed back from the row, and assert that no token of another seat's charge and no part of the seed appears anywhere in the bytes of the answer — so a secret column added by a later migration fails here until someone redacts it.
  • [ ] The test proves it is testing something: a seated player's own charge is present in their own read, and the assertion fails loudly if a table was not dealt.
  • [ ] An admin is a role of the repository, not a seat: an admin holding no seat sees no charge, in one named case.
  • [ ] A failure prints the seed, the viewer and the door, so the run can be reproduced from the line the test printed.
  • [ ] Settled tables are out of scope on purpose — by §9 everything is public once a table settles, and #47 owns that. This test walks open and playing tables only, and says so in a comment.

Files src/secret.test.ts (new), and at most a small export from src/routes.ts / src/tty.ts so the test can enumerate them.

Risks A property test that silently covers nothing is worse than no test: the "own charge is present" assertion is what keeps it honest. It is a guard, not the redaction — the rule stays in the action, and if this test has to reach into a door to pass, the door is deciding something it should not.

Brief that fits @mason to build, @sentinel to review what counts as a leak. (A person assigns.)

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs