Skip to content

Feat/submit a game - #21

Draft
HarryCordewener wants to merge 2 commits into
mainfrom
feat/submit-a-game
Draft

Feat/submit a game#21
HarryCordewener wants to merge 2 commits into
mainfrom
feat/submit-a-game

Conversation

@HarryCordewener

Copy link
Copy Markdown
Member

No description provided.

HarryCordewener and others added 2 commits July 31, 2026 11:24
Found by the first crawl large enough to find it: seeding 701 addresses from the
directories, three games of four hundred died with

  54000: index row size 3048 exceeds btree version 4 maximum 2704
         for index "game_field_field_value_idx"

PostgreSQL cannot index a btree row past about 2704 bytes, and a connect screen
is routinely thousands of characters -- the longest in this catalogue is 9,376.
The failure is total rather than partial: the INSERT is refused, so the whole
probe's ingestion is lost for that game, and it is lost again on every future
probe. A game with a generous piece of ASCII art was permanently unlistable and
nothing said so.

WHY THREE AND NOT FIFTY-ONE, WHICH IS HOW MANY ROWS ARE NOW OVER THAT SIZE.
Index tuples cannot be stored out of line but they can be compressed, so whether
a game was listable depended on how well its ASCII art compressed. That is why
it presented as three unrelated failures rather than as a rule, and it is why
looking at the length of the longest value would not have predicted it.

Both indexes over game_field had the flaw, and the first fix caught only one --
the very next probe failed on the other. They are bounded differently because
they are read differently:

  - game_field_field_value_idx serves §9's faceted search and is indexed on a
    256-character prefix. Nothing has ever searched by connect screen and nothing
    will; it is a display asset, and its fingerprint has its own column.

  - game_field_folded_value_idx serves §7.3's identity lookup, which asks an
    equality question. A prefix there would silently turn that into a
    starts-with -- over-matching where the raw index merely refused -- so it is
    partial instead, and CatalogueDirectories carries the same predicate or the
    planner cannot use it. Every identity signal §7.3 names is short: a name, a
    year, a hostname, a hash, a token. A value longer than that is not one.

THE STORED VALUE IS UNTOUCHED. Truncating what a game sent in order to fit our
own index would be the quiet lossiness this schema refuses everywhere else. It is
the index that is bounded, never the fact.

The test asserts the property over EVERY index on game_field rather than over the
one that was noticed, which is the mistake the first pass made.

Verified against the live catalogue: the games that had been failing re-probed
clean, and the one that raised the original error now holds its 7,535-character
connect screen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Half the feature: the schema and the reads. The form and the scope gate follow.

A signed-in operator may add their own game, and it stays off the listing until a
claim proves they run it. That is ONE NULLABLE COLUMN and one sentence:

    a game is public if nobody submitted it, or if it has been claimed.

game.submitted_by is not a lifecycle state and could not be. `state` is derived
from availability history and never set by hand, and this is a different axis
entirely -- how a game reached us rather than how it has been behaving. Two axes
in one column would leave a submitted game that goes dark unable to say both
things.

WHY THE ASYMMETRY WITH §7.1's AUTO-LISTING IS NOT ARBITRARY. Discovery is
something we did: a referral we walked and a resolved-address gate we applied. A
submission is a stranger pointing us at a host. If it listed on sight, the form
would be a way to put any address on a public page under any description, and the
answer to "who says this is a game" would be "somebody". Requiring the claim
makes the form mean add YOUR game rather than add A game.

AND IT IS NOT THE MODERATION QUEUE §3 CONDEMNS. The incumbents' queues waited on
a human at their end, which is why listings sat unapproved for a year. This waits
on the submitter, settles in one probe, and has nobody in the middle. The
migration says so, because the day somebody adds a staff approval screen the
distinction is gone and so is the argument for the feature.

The rule is one constant applied to all seven public reads. Writing the predicate
per query is how the eighth query gets added without it, and the failure mode is
a game on a public page nobody vouched for. FOUR OF THE SIX SQL LITERALS WERE NOT
INTERPOLATED, so `{Public}` would have gone to PostgreSQL as text -- it compiled
cleanly and would have failed at runtime, which is exactly why the suite runs
against a real database rather than a fake.

The guard is a test that walks IGameQueries by reflection and requires every
member to be named as considered, so a query added later fails until somebody
decides whether a submitted game can reach it. Alongside it, the case that would
have been catastrophic to get backwards: an unclaimed game the crawler found is
still listed. Reading the column as "unclaimed games are hidden" rather than
"unclaimed SUBMISSIONS are hidden" would have emptied the catalogue -- all 409
games in it are unclaimed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 5a27ec0c-038e-450e-a7fe-49df07b76819

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Comment @coderabbitai help to get the list of available commands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant