Skip to content

An about page, and the attribution it owes - #12

Merged
HarryCordewener merged 1 commit into
chore/park-the-importerfrom
feat/about-page
Jul 31, 2026
Merged

An about page, and the attribution it owes#12
HarryCordewener merged 1 commit into
chore/park-the-importerfrom
feat/about-page

Conversation

@HarryCordewener

Copy link
Copy Markdown
Member

Stacks on #11 (chore/park-the-importer), which is main plus #9 and #11 — the branch that rewrote how the site gets its data and what the backfill is allowed to take. Review after that lands; the diff against main will otherwise carry #11's changes too.

There was no /about route. Spec §7.6 and §11 both require one, and it is an obligation this project already incurred by crawling other people's directories and dialling other people's servers.

What the page says

  • The measured-vs-declared spine. Both sides shown, both labelled, the disagreement kept rather than averaged. A player count comes from a pre-login WHO/DOING or from MSSP PLAYERS, and says which. An unreadable WHO is uncountable; a measured zero is a zero.
  • Reachable, never uptime, in the vocabulary the rest of the site uses — a socket from one vantage point, which does not measure whether the game was up.
  • The known limitations in the spec's own words. Archive grace is a quarter of the reachable time we probed, floored at 60 days, so a game running since 1995 starts at the floor on the day we find it; MSSP CREATED is never credited, because it is one hand-typed line and crediting it would make the threshold gameable.
  • Attribution for every directory in docs/import-sources.md, with what is taken from them — addresses only, no counts, no history, no provenance — and the three reasons §7.6 gives. The MudStats entry carries the record of the 143-page crawl that went out before anyone had written to them, because that record matters most on the page asking to be trusted about everything else.
  • The crawler: what one probe does, CRAWL DELAY beating our own floor, a referred host resolved and refused unless every address is globally routable, connect screens taken down on request, and how to ask us to stop.
  • What we never do: no votes/ratings/vote-driven rankings, no forums/reviews/wikis/comments, player names never persisted, no absolute population figure.
  • Licence: code MIT; the data licence stated as an open question (§15.2), with the deployment's configured terms shown as this deployment's answer rather than the project's.

How it is built

Blazor static SSR, no script, no interactivity. AboutPage is one view model; About.razor and PlainText.RenderAbout are two renderings of it, so a sentence cannot exist on the graphical page and not in ?plain=1 — asserted by rendering the component and comparing it to the plain text. One line added to MainLayout.razor; CSS appended at the end of app.css under its own header.

What it deliberately does not claim

Three places where the design describes behaviour the deployment does not have, and the page says so rather than reciting the spec:

  1. The opt-out is not advertised as automated. Neither the MSSP field nor the DNS TXT record exists in code (grep finds no opt-out anywhere), so the page says there is none yet and that asking a person works.
  2. The crawler is not said to identify itself. ProbeOptions.TerminalTypes and InfoUrl are read by nothing: TelnetNegotiationCore's client-mode TerminalTypeProtocol hardcodes TNC/XTERM/MTTS 3853 in a private field with no setter, and NewEnvironProtocol answers a server's request with the crawler host's own USER and a fixed LANG. So an admin's logs show the library and a local account name, not us. Both are documented where the options are declared, and both are a PR to TNC — never a reflection hack here. The page tells an admin the one thing that is true and useful: the shape of the visit.
  3. An unconfigured contact address is marked as the placeholder it is, rather than published as the way to reach us. The default InfoUrl is on a domain nobody has chosen (§15.1).

No number on the page is one that would have had to be invented. The recorded import run's yields (805 targets across 745 hosts) are left in docs/import-sources.md: they describe a database that is not necessarily the one serving the page.

Tests

tests/MUI.Web.Tests/AboutPageTests.cs, 19 tests. The load-bearing one parses docs/import-sources.md and asserts every source under ## Read is credited by name and by address — a copied list could not catch a source added to the record and not to the page. The rest assert sentences: the grace limitation, the CREATED refusal, the crawl-delay and referral facts, that uptime appears twice and both are refusals, that the crawler identity is read off ProbeOptions rather than typed in (checked by building the page from a different ProbeOptions), that the permitted command list comes from TelnetProbe.PermittedCommands, plain-mode 80-column width, and graphical/plain parity off a rendered frame.

dotnet build MUIndex.slnx -c Release clean; all five suites green (Web 130, Crawl 130, Discovery 182, Catalog 133, Crawler 77).

🤖 Generated with Claude Code

https://claude.ai/code/session_01NrGKmKcRCGktyhRTFbQDMk

/about, which spec §7.6 and §11 both require and neither calls a feature: it
is an obligation incurred by crawling other people's sites and dialling other
people's servers.

It carries the measured-vs-declared spine, the vocabulary rule that a socket
from one vantage point is reachability and never uptime, the stated known
limitation that archive grace is computed only from reachable time we probed
(so a game running since 1995 starts at the floor on the day we find it, and
MSSP CREATED buys nothing), the four directories the backfill read plus the
one it has chosen not to, what is taken from them — addresses, nothing else —
and why, the crawler's identity and the shape of a probe, and the licence
position: MIT code, and a data licence that is still an open question rather
than one settled by accident.

Both surfaces render one view model, so a sentence cannot exist on the
graphical page and not in ?plain=1. The attribution list is pinned against
docs/import-sources.md by parsing it: a source added to the record and not to
the page is the failure worth catching, and a copied list cannot catch it.

Three things it deliberately does not claim. The opt-out is not advertised as
automated, because neither the MSSP field nor the DNS TXT record the design
describes exists in code and a switch wired to nothing is worse than none.
The crawler is not said to identify itself: TelnetNegotiationCore hardcodes a
client's terminal types with no setter and answers NEW-ENVIRON from the host's
own environment, so ProbeOptions.TerminalTypes and InfoUrl reach no server —
both now documented where they are declared, and both a PR upstream rather
than a reflection hack here. And an unconfigured contact address is marked as
the placeholder it is instead of published as the way to reach us.

No figure on the page is one we would have had to invent; the one recorded
run's yields are left to the record, since they describe a database that is
not necessarily this one.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NrGKmKcRCGktyhRTFbQDMk
@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in: 20 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 308abe1a-410b-46cf-ac97-e36b25c1cd50

📥 Commits

Reviewing files that changed from the base of the PR and between 2caff7f and 8532472.

⛔ Files ignored due to path filters (6)
  • docs/screenshots/01-home-feeds.png is excluded by !**/*.png
  • docs/screenshots/02-games-listing.png is excluded by !**/*.png
  • docs/screenshots/03-game-page.png is excluded by !**/*.png
  • docs/screenshots/04-plain-mode.png is excluded by !**/*.png
  • docs/screenshots/05-archive.png is excluded by !**/*.png
  • docs/screenshots/06-mobile-game.png is excluded by !**/*.png
📒 Files selected for processing (98)
  • .github/workflows/ci.yml
  • .gitignore
  • CLAUDE.md
  • MUIndex.slnx
  • README.md
  • docs/import-sources.md
  • docs/screenshots/README.md
  • docs/specs/2026-07-30-mu-directory-design.md
  • migrations/0002_game_field.sql
  • migrations/0003_presence_sample.sql
  • migrations/0004_availability_interval.sql
  • migrations/0100_import_provenance.sql
  • src/MUI.Catalog/ArchivePolicy.cs
  • src/MUI.Catalog/Persistence/ArchiveSweeper.cs
  • src/MUI.Catalog/Persistence/FieldRegistry.cs
  • src/MUI.Catalog/Persistence/NpgsqlAvailabilityStore.cs
  • src/MUI.Catalog/Persistence/NpgsqlGameQueries.cs
  • src/MUI.Catalog/Persistence/Records.cs
  • src/MUI.Catalog/Persistence/SqlEnums.cs
  • src/MUI.Catalog/Persistence/Stores.cs
  • src/MUI.Catalog/Provenance.cs
  • src/MUI.Catalog/Views.cs
  • src/MUI.Crawl/BannerText.cs
  • src/MUI.Crawl/MsspReport.cs
  • src/MUI.Crawl/ProbeOptions.cs
  • src/MUI.Crawl/TelnetProbe.cs
  • src/MUI.Crawl/WireText.cs
  • src/MUI.Discovery/BannerFingerprint.cs
  • src/MUI.Discovery/Identity.cs
  • src/MUI.Import/DirectoryFetcher.cs
  • src/MUI.Import/EtiquettePlanner.cs
  • src/MUI.Import/HistorySink.cs
  • src/MUI.Import/IDirectorySource.cs
  • src/MUI.Import/IImportWriter.cs
  • src/MUI.Import/ImportEtiquette.cs
  • src/MUI.Import/ImportIdentity.cs
  • src/MUI.Import/ImportPipeline.cs
  • src/MUI.Import/ImportProvenance.cs
  • src/MUI.Import/ImportReport.cs
  • src/MUI.Import/ImportRunner.cs
  • src/MUI.Import/ImportTier.cs
  • src/MUI.Import/ImportedAvailabilityWriter.cs
  • src/MUI.Import/ImportedGame.cs
  • src/MUI.Import/MUI.Import.csproj
  • src/MUI.Import/MeasuredHistorySink.cs
  • src/MUI.Import/NpgsqlImportProvenanceStore.cs
  • src/MUI.Import/PolitenessGate.cs
  • src/MUI.Import/RobotsPolicy.cs
  • src/MUI.Import/ServiceCollectionExtensions.cs
  • src/MUI.Import/SourceAttribution.cs
  • src/MUI.Import/Sources/HtmlLine.cs
  • src/MUI.Import/Sources/MsspCrawlerTable.cs
  • src/MUI.Import/Sources/MudStatsSource.cs
  • src/MUI.Import/Sources/TinTinMsspCrawlerSource.cs
  • src/MUI.Web/Components/AboutPage.cs
  • src/MUI.Web/Components/ActivityHeatmap.razor
  • src/MUI.Web/Components/ActivitySummary.cs
  • src/MUI.Web/Components/Layout/MainLayout.razor
  • src/MUI.Web/Components/Pages/About.razor
  • src/MUI.Web/Components/PlainText.cs
  • src/MUI.Web/Components/ReachSeries.cs
  • src/MUI.Web/Data/PostgresData.cs
  • src/MUI.Web/Program.cs
  • src/MUI.Web/wwwroot/app.css
  • tests/MUI.Catalog.Tests/ArchivePolicyTests.cs
  • tests/MUI.Catalog.Tests/FieldPrecedenceTests.cs
  • tests/MUI.Catalog.Tests/Persistence/ArchiveSweeperTests.cs
  • tests/MUI.Catalog.Tests/Persistence/AvailabilityStorePostgresTests.cs
  • tests/MUI.Catalog.Tests/Persistence/Support/InMemoryPersistence.cs
  • tests/MUI.Crawl.Tests/ProbeSessionTests.cs
  • tests/MUI.Crawl.Tests/WireTextTests.cs
  • tests/MUI.Crawler.Tests/CrawlCyclePostgresTests.cs
  • tests/MUI.Crawler.Tests/Support/InMemoryCatalogue.cs
  • tests/MUI.Import.Tests/AttributionTests.cs
  • tests/MUI.Import.Tests/EtiquetteTests.cs
  • tests/MUI.Import.Tests/Fixtures/mudstats-index.html
  • tests/MUI.Import.Tests/Fixtures/mudstats-world-4dimensions.html
  • tests/MUI.Import.Tests/Fixtures/tintin-mssp-mudlist.html
  • tests/MUI.Import.Tests/HistoryTierTests.cs
  • tests/MUI.Import.Tests/ImportAgainstPostgresTests.cs
  • tests/MUI.Import.Tests/ImportPipelineTests.cs
  • tests/MUI.Import.Tests/ImportTierTests.cs
  • tests/MUI.Import.Tests/MUI.Import.Tests.csproj
  • tests/MUI.Import.Tests/RobotsAndRateLimitTests.cs
  • tests/MUI.Import.Tests/Sources/MudStatsSourceTests.cs
  • tests/MUI.Import.Tests/Sources/TinTinMsspCrawlerSourceTests.cs
  • tests/MUI.Import.Tests/Support/FakeHttp.cs
  • tests/MUI.Import.Tests/Support/Fixture.cs
  • tests/MUI.Import.Tests/Support/Harness.cs
  • tests/MUI.Import.Tests/Support/InMemoryStores.cs
  • tests/MUI.Import.Tests/Support/ManualTimeProvider.cs
  • tests/MUI.Import.Tests/Support/PostgresFixture.cs
  • tests/MUI.Web.Tests/AboutPageTests.cs
  • tests/MUI.Web.Tests/PlainParityTests.cs
  • tests/MUI.Web.Tests/SilenceIsNotEvidenceTests.cs
  • tests/MUI.Web.Tests/ThreeStatesTests.cs
  • tools/live-tintin-import/Program.cs
  • tools/live-tintin-import/live-tintin-import.csproj

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
@HarryCordewener
HarryCordewener merged commit f5be15b into main Jul 31, 2026
3 checks passed
@HarryCordewener
HarryCordewener deleted the feat/about-page 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