Skip to content

WI-047: A licence per picture

WI-047: A licence per picture

Wikidata has photographs of board games (P18) and the bytes live on upload.wikimedia.org, which robots.txt permits outright. The images were never the problem.

The licence is, and it differs file by file. Four images from one harvest came back CC0, CC BY-SA 3.0 and CC BY-SA 4.0 — and two more were refused as GFDL and bare “Attribution”. WI-072 put the rule in the database: material that cannot be credited is not stored.

30 games, 9 with an image → 4 resolved, 2 refused
root CC0-1.0 by murphzero
feudum CC-BY-SA-4.0 by El Pantera
caesar-cleopatra CC-BY-SA-3.0 by Matěj Baťha
quixo CC-BY-SA-4.0 by El Pantera
cafe-international refused — licence "GFDL" is not one we know how to credit
ludo refused — licence "Attribution" is not one we know how to credit

The permitted source is the one without the licence

SourceLicence?robots.txt
api.wikimedia.org/core/v1/commons/file/…noallowed
Commons Special:EntityData/M….json (P275)yesdisallowed
commons.wikimedia.org/w/api.php, /w/rest.phpyesdisallowed
Commons file page /wiki/File:X.jpgyesallowed

So ADR-0016’s “prefer structured endpoints over rendered pages” inverts here, and is amended rather than quietly reinterpreted. Commons publishes machine-readable fields on that page for reusers, which makes it far less fragile than scraping usually is.

Three decoys, each a confident wrong answer

  • <link rel="license" href=".../by-sa/4.0/"> is Commons’ own page licence, on every file page. Reading it labels the entire catalogue CC BY-SA 4.0 — uniform, plausible, and wrong every time. It was wrong for both files first tested, which were 2.5 and 3.0.
  • publicdomain/zero/1.0 appears in the page furniture regardless of the file.
  • The uploader from the REST endpoint is not necessarily the author.

The parser refuses rather than falls back, and the fixtures include all three decoys — a fixture without them passes against a parser that reads the wrong link.

And one that nearly stopped it working at all

Commons writes _ in class attributes as &#95;, so licensetpl_short does not appear in the markup and a direct search finds nothing. The first probe reported no licence template on a page that plainly had one.

Definition of done

  • The licence, its URL and the author are read from the file page.
  • A licence not on the allowlist is refused, not approximated.
  • A file with no named author is refused — CC BY requires naming them.
  • None of the three decoys can be mistaken for the licence.
  • Refusals are reported per file, with a reason.
  • Credits name the creator, not just the platform.
  • Each check proven able to fail.
  • Gate green.

Verification

Terminal window
pnpm --filter @tabletop/catalogue-forge test
pnpm --filter @tabletop/catalogue test
pnpm gate

Seeded failures

SeedBit
Fall back to the page’s own rel=license1
Accept a licence we do not recognise1
Ship an image with no named author1
Stop unescaping class names8

A guard in packages/catalogue also fired as designed: ATTRIBUTION_REQUIRED was pinned to a single licence so that widening it is a decision. Widening it for images broke that test, which is exactly what it is for.

Not done here — no cover is on a screen yet

The pipeline resolves an image and its credit and writes both onto a game. Nothing renders one. That needs a games.image_url column and migration, the API returning it alongside its credit, and the app and site showing it with the credit attached — and CC BY-SA obliges that credit wherever the picture appears, which makes the rendering the substantial half rather than the easy one.

Split deliberately: this half is proven against live data, and shipping it separately keeps the licensing reviewable on its own.