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 murphzerofeudum CC-BY-SA-4.0 by El Panteracaesar-cleopatra CC-BY-SA-3.0 by Matěj Baťhaquixo CC-BY-SA-4.0 by El Pantera
cafe-international refused — licence "GFDL" is not one we know how to creditludo refused — licence "Attribution" is not one we know how to creditThe permitted source is the one without the licence
| Source | Licence? | robots.txt |
|---|---|---|
api.wikimedia.org/core/v1/commons/file/… | no | allowed |
Commons Special:EntityData/M….json (P275) | yes | disallowed |
commons.wikimedia.org/w/api.php, /w/rest.php | yes | disallowed |
Commons file page /wiki/File:X.jpg | yes | allowed |
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.0appears 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 _, 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
pnpm --filter @tabletop/catalogue-forge testpnpm --filter @tabletop/catalogue testpnpm gateSeeded failures
| Seed | Bit |
|---|---|
Fall back to the page’s own rel=license | 1 |
| Accept a licence we do not recognise | 1 |
| Ship an image with no named author | 1 |
| Stop unescaping class names | 8 |
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.