Skip to content

The ecosystem dashboard, and rankings that say what they rank on - #13

Merged
HarryCordewener merged 1 commit into
feat/about-pagefrom
feat/ecosystem-dashboard
Jul 31, 2026
Merged

The ecosystem dashboard, and rankings that say what they rank on#13
HarryCordewener merged 1 commit into
feat/about-pagefrom
feat/ecosystem-dashboard

Conversation

@HarryCordewener

@HarryCordewener HarryCordewener commented Jul 31, 2026

Copy link
Copy Markdown
Member

Spec §9's ecosystem dashboard and rankings, both in §14's v1 boundary and neither previously
existing.

Stacks on #11 (chore/park-the-importer), which is main plus #9 and #11. Those two rewrote how
the site gets its data, and building on main would have meant writing against the fixture and stale
wording. Review after #11 lands, or read the diff against that branch.

What is here

Two pages, /ecosystem and /rankings, both static SSR with no script, both surviving ?plain=1
whole. Aggregates live in NpgsqlGameQueries behind IGameQueries; MUI.Catalog references nothing
new.

Shares, never totals. §15.7 withholds the absolute "how many people play MU*" figure because a
ratio over the games we reached survives the ones we cannot reach and the ones nobody claimed, and a
headcount survives neither. EcosystemDashboard has nowhere to put one — it has no access to
presence at all — and NoAbsolutePlayerFigureIsEmittedByEitherSurface sums the fixture's measured
counts and requires the number never to appear on either surface.

A share carries its denominator as a field. MeasuredShare(Label, Count, Denominator), with
Fraction computable from nothing else, so a percentage cannot travel to a renderer without the set
it is a fraction of. Protocols carry two denominators, because they are two sets: games whose
handshake we completed, and games whose MSSP report we hold.

The protocol denominator is read off availability, not off capability rows. A reachable
interval is a session of ours that completed, which is exactly what a measured capability is a
capability of. Counting "games that have capability rows" would define the denominator out of the
numerator — a game whose handshake completed and offered nothing measurable would drop out of the
bottom of every fraction and quietly raise every share on the page.

What the stored data could not honestly support, and what the page says instead

  • No adoption curve. game_field holds a current value with transitions beside it in
    field_change, so a curve has to be reconstructed from transitions and there are not yet enough to
    plot. The available alternative — plotting each observation's first_seen_at — would draw a
    confident rising line measuring our crawler reaching more games and nothing whatever about anybody
    adopting anything. The page says so and prints the transition count, which is the number that says
    when the curve becomes real.
  • TLS is unmeasured and reads as unmeasured, not as 0%. The probe dials plain telnet, TLS is not
    a telnet option, and nothing writes a tls endpoint — so no capability.tls.measured row can
    exist today. ProtocolAdoption.Offered is nullable for exactly this, and the null is derived from
    the tally rather than compiled in, so the column starts reporting a share on its own the day the
    first measurement lands. TLS still shows a declared share, over its own denominator.
  • The measured column is a floor, and is labelled one. FieldObservations writes a capability
    when it observes one and otherwise writes nothing, because the crawler requests MSSP alone and
    declines MCCP outright. MSSP is the one protocol whose silence is an answer — we ask by name — so
    it is the only one whose absence is counted as a no. Everything else lands in neither offered
    nor asked
    .

Rankings

Two tables, each stating its basis on the page: busiest by the median of measured concurrent
counts over a named week among games that produced at least 24 counted samples (percentile_disc, so
the median is a number some probe actually read), and the current unbroken reachable spell, which
carries the date it began because a spell cannot be longer than we have been watching. Archived games
are out of both and of nothing else. An uncountable probe is not a zero in either; a measured zero is
a count and ranks. There is no voting affordance and the page says there never will be.

Tests

670 across the five suites, all green and warning-free. Worth naming:

  • NoAbsolutePlayerFigureIsEmittedByEitherSurface
  • EveryPercentageOnTheDashboardArrivesWithItsDenominator
  • AGameWeHaveNeverHandshakedIsOutOfTheDenominatorRatherThanInItAsANo
  • AHandshakeThatOfferedNothingIsStillInTheDenominator
  • AProtocolNothingHasOfferedIsUnmeasuredRatherThanNoughtPerCent
  • OnlyAProtocolWeAskedForCountsSilenceAsANo
  • AnUncountableProbeIsNotAZeroInARanking

Two things outside the feature

  • The fixture's demo week is scaled to each game's own count. It peaked at 17 for every game
    regardless of the count that game reports, which made the demo ranking five ties.
  • The test container's client limit is lifted to 500. A database per test met Postgres's default 100
    on the run that took the suite past 130 tests, failing whichever tests happened to be starting and
    reading as a flake in twenty unrelated places.

Deliberately not here

No /api/ecosystem — §10 is a separate surface and this adds no endpoint. No recency window on the
protocol denominator: a listed game we handshaked six weeks ago is in it, and the page states how old
the stalest handshake in the picture is rather than silently trimming the set.

🤖 Generated with Claude Code

https://claude.ai/code/session_01NrGKmKcRCGktyhRTFbQDMk

@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

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: ba893d4b-3eac-43dc-b538-9f7401b72a05

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.

@HarryCordewener
HarryCordewener changed the base branch from main to chore/park-the-importer July 31, 2026 15:18
…ares of

Spec §9's ecosystem dashboard and rankings, both computed from measured data and
neither able to say the thing a directory is usually asked for.

Shares, never totals. §15.7 withholds the absolute "how many people play MU*"
figure because a ratio over the games we reached survives the ones we cannot and
the ones nobody claimed, and a headcount survives neither — so EcosystemDashboard
has nowhere to put one, and a test sums the fixture's counts and requires the
number never to appear.

A share carries its denominator as a field, not as a caption. MeasuredShare holds
the count and the set it was counted in, and Fraction can be computed from nothing
else, so a percentage cannot travel to a renderer without the set it is a fraction
of. Protocols carry two denominators because they are two sets: games whose
handshake we completed, and games whose MSSP report we hold.

Three things the data could not honestly support, said on the page rather than
filled in:

- There is no adoption curve. game_field holds a current value with transitions
  beside it, so a curve has to be reconstructed and there are not yet enough
  transitions to plot. The available alternative — plotting each observation's
  first sighting — would draw a confident rising line measuring the crawl reaching
  more games and nothing about anybody adopting anything. The transition count is
  on the page instead, which is the number that says when the curve becomes real.
- TLS is unmeasured, and says so rather than reading 0%. The probe dials plain
  telnet and TLS is not a telnet option, so no capability.tls.measured row can
  exist; "0% of games offer TLS" would be a limit of our crawler published as a
  fact about the hobby. The rule is derived from the tally rather than compiled
  in, so the column starts reporting a share the day the first measurement lands.
- The measured column is a floor and is labelled one. The crawler writes a
  capability down when it observes it and otherwise writes nothing, because it
  requests MSSP alone and declines MCCP outright — MSSP is the one protocol whose
  silence is an answer, and it is the only one whose absence is counted as a no.

The protocol denominator is read off availability rather than off capability rows:
a reachable interval is a session of ours that completed, which is what a measured
capability is a capability of. Counting games that have capability rows instead
would define the denominator out of the numerator and quietly raise every share.

Rankings are busiest-by-median over a stated week among games with enough samples
to have a median, and the current unbroken reachable spell, which carries the date
it began because a spell cannot be longer than we have been watching. Archived
games are out of both and of nothing else. An uncountable probe is not a zero in
either, and a measured zero is a count and ranks.

The §5.1 ladder is resolved in SQL for the first time, because the dashboard reads
every game at once. It is passed as a parameter generated from the enum's declared
order, so the ladder still has exactly one spelling.

Also: the fixture's demo week is scaled to each game's own count, so a demo
ranking is a ranking rather than five ties; and the test container's client limit
is lifted, because a database per test met Postgres's default hundred on the run
that took the suite past a hundred and thirty tests and reported it as a flake in
twenty unrelated places.
@HarryCordewener
HarryCordewener changed the base branch from chore/park-the-importer to feat/about-page July 31, 2026 15:21
@HarryCordewener
HarryCordewener force-pushed the feat/ecosystem-dashboard branch from 5a4a6ac to 3cb6618 Compare July 31, 2026 15:21
@HarryCordewener
HarryCordewener merged commit 7026fa6 into main Jul 31, 2026
1 check passed
@HarryCordewener
HarryCordewener deleted the feat/ecosystem-dashboard branch July 31, 2026 15:53
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