This commit is contained in:
2026-11-05 09:57:11 -05:00
parent d34388bf2c
commit 89e392cc2e
81 changed files with 12410 additions and 1135 deletions
+38 -9
View File
@@ -2,16 +2,43 @@
## Shipped source coverage
The bundle follows **all 80 actual Latin names** in [the botany catalogue](../mods/hearth/botany.lua), not their sometimes ambiguous common names. The maintenance run on **2026-11-03 UTC** queried all 80 names using eight MediaWiki API batches of ten, with at most two requests in flight.
The bundle follows **all 100 actual Latin names** in [the botany catalogue](../mods/hearth/botany.lua), not their sometimes ambiguous common names. The approved maintenance `--refresh` run on **2026-11-03 UTC** queried all 100 names using ten MediaWiki API batches of ten, with at most two requests in flight, using the absolute installed Node executable and only the hardcoded English Wikipedia API URL.
**78 entries contain real English Wikipedia plaintext introductions. Two entries contain original availability notes, not Wikipedia quotations:**
**98 entries contain real English Wikipedia plaintext introductions (78 previous + 20 new). Two entries contain original availability notes, not Wikipedia quotations:**
| Game ID | Exact catalogue Latin name | Source status |
| --- | --- | --- |
| `old_mans_beard` | *Usnea subfloridana* | [Exact species page](https://en.wikipedia.org/wiki/Usnea_subfloridana) missing |
| `cup_lichen` | *Cladonia chlorophaea* | [Exact species page](https://en.wikipedia.org/wiki/Cladonia_chlorophaea) missing |
For both missing species, the API explicitly returned `missing: true`; separate exact-page and REST-summary checks returned HTTP 404. No genus, species complex, similarly named lichen, invented revision, or synthetic Wikipedia prose was substituted. Consequently **80 actual species article excerpts are blocked by source availability**. The original notes make this visible to offline players. Refresh can pick up an article if Wikipedia creates one later.
For both missing species, the refreshed API explicitly returned `missing: true`; separate exact-page and REST-summary checks in the previous 80-species maintenance run returned HTTP 404. No genus, species complex, similarly named lichen, invented revision, or synthetic Wikipedia prose was substituted. Consequently **100 actual species article excerpts are blocked by source availability**. The original notes make this visible to offline players. Refresh can pick up an article if Wikipedia creates one later. All previous 78 introduction texts and two availability-note texts were preserved exactly (verified by matching SHA-256 over ordered ID/text/kind records before and after refresh); retrieval timestamps were refreshed from actual batch completion times.
### Twenty newly cached species references
All twenty new exact catalogue names resolved directly to the same Wikipedia title, without guessed aliases. Each entry contains an actual plaintext introduction, positive page/revision IDs, the API revision timestamp, actual retrieval timestamp, contributor attribution/history, and CC BY-SA 4.0 licensing. Retrieval occurred between **2026-11-03T19:54:51.978Z** and **2026-11-03T19:54:52.400Z**; per-entry timestamps are retained in the bundle. None of these additions required an availability note or shortening.
| Game ID | Exact catalogue Latin name / Wikipedia source title | Page ID | Permanent source revision |
| --- | --- | --- | --- |
| `crab_apple` | *Malus sylvestris* | 5958504 | [1380105044](https://en.wikipedia.org/w/index.php?oldid=1380105044) |
| `wild_cherry` | *Prunus avium* | 28331736 | [1380998001](https://en.wikipedia.org/w/index.php?oldid=1380998001) |
| `field_maple` | *Acer campestre* | 437923 | [1366038360](https://en.wikipedia.org/w/index.php?oldid=1366038360) |
| `honeysuckle` | *Lonicera periclymenum* | 811057 | [1354922261](https://en.wikipedia.org/w/index.php?oldid=1354922261) |
| `ivy` | *Hedera helix* | 5372245 | [1382798111](https://en.wikipedia.org/w/index.php?oldid=1382798111) |
| `gorse` | *Ulex europaeus* | 2482094 | [1382611269](https://en.wikipedia.org/w/index.php?oldid=1382611269) |
| `broom` | *Cytisus scoparius* | 510118 | [1351345770](https://en.wikipedia.org/w/index.php?oldid=1351345770) |
| `dandelion` | *Taraxacum officinale* | 10783290 | [1371025491](https://en.wikipedia.org/w/index.php?oldid=1371025491) |
| `daisy` | *Bellis perennis* | 1157853 | [1375045201](https://en.wikipedia.org/w/index.php?oldid=1375045201) |
| `red_clover` | *Trifolium pratense* | 1900302 | [1371055360](https://en.wikipedia.org/w/index.php?oldid=1371055360) |
| `birdsfoot_trefoil` | *Lotus corniculatus* | 1117322 | [1379332042](https://en.wikipedia.org/w/index.php?oldid=1379332042) |
| `ribwort_plantain` | *Plantago lanceolata* | 1250244 | [1377190915](https://en.wikipedia.org/w/index.php?oldid=1377190915) |
| `selfheal` | *Prunella vulgaris* | 12058348 | [1380124722](https://en.wikipedia.org/w/index.php?oldid=1380124722) |
| `knapweed` | *Centaurea nigra* | 21631605 | [1366977479](https://en.wikipedia.org/w/index.php?oldid=1366977479) |
| `oxeye_daisy` | *Leucanthemum vulgare* | 567709 | [1381123379](https://en.wikipedia.org/w/index.php?oldid=1381123379) |
| `field_scabious` | *Knautia arvensis* | 12057909 | [1371147715](https://en.wikipedia.org/w/index.php?oldid=1371147715) |
| `teasel` | *Dipsacus fullonum* | 4298215 | [1375022541](https://en.wikipedia.org/w/index.php?oldid=1375022541) |
| `cow_parsley` | *Anthriscus sylvestris* | 2649495 | [1375096601](https://en.wikipedia.org/w/index.php?oldid=1375096601) |
| `garlic_mustard` | *Alliaria petiolata* | 509457 | [1375930171](https://en.wikipedia.org/w/index.php?oldid=1375930171) |
| `holly_fern` | *Polystichum setiferum* | 5025872 | [1296456929](https://en.wikipedia.org/w/index.php?oldid=1296456929) |
Five catalogue names resolved through Wikipedia's own title redirects in this snapshot:
@@ -34,7 +61,7 @@ These are API-reported redirects, not guessed mappings or search results. The ca
- `/inspect` observes the first pointed node within **six blocks of the player's eye**, using a bounded ray and `get_node_or_nil`. Unknown or unloaded first surfaces stop inspection; nothing is emerged, force-loaded, harvested, placed or written. Species-specific seasonal plants, tree stems/stages, logs and leaves resolve through the actual `botany.kind()` API. Generic unnamed vegetation is not assigned an invented species.
- `/inspect oak` or `/inspect Quercus robur` opens an exact catalogue ID or canonical Latin name. Matching is exact and case-sensitive (surrounding whitespace is allowed), not fuzzy, common-name search or an arbitrary URL. `/botany [search]` remains the literal-search catalogue browser.
- Field notes offer **Inspect target**. The Botanical guide keeps its ten-row pages and adds a **Species article** dropdown/button for those rows. Selections are bounded numeric indices into the server session's current-page IDs, never submitted IDs or URLs. A HUD hint on known botanical targets advertises `/inspect species` (replace “species” with an ID, or use bare `/inspect` for the target). No harvesting or building callbacks are hijacked.
- The **Article** tab displays **Wikipedia excerpt (offline)** for the 78 real introductions. The two missing species use **No Wikipedia article cached (offline)** and show their original CC0 availability notes, never fake Wikipedia prose or revisions. No HTML, embedded browser or full-article availability is claimed.
- The **Article** tab displays **Wikipedia excerpt (offline)** for the 98 real introductions. The two missing species use **No Wikipedia article cached (offline)** and show their original CC0 availability notes, never fake Wikipedia prose or revisions. No HTML, embedded browser or full-article availability is claimed.
- **Current effects** comes directly from `species_effects.describe(record)`: **SIMULATED** and **DESCRIPTIVE (not simulated)** are separate labels. Reviewed evidence notes and evidence URLs are distinct from snapshot identity provenance. The excerpt may omit the body section supporting an effect; numbers, timings, niche thresholds and budgets remain game policy, not measurements from Wikipedia.
- Body text is limited to **8,000 Unicode code points**, in pages of **4,000**. All current introductions fit one page unchanged (maximum 3,417). Any reader-side cap is disclosed. Unnamed read-only, selectable textareas show source title, attribution, license/link, canonical URL, permanent revision URL, contributor history, revision/retrieval timestamps and changes. Links are copyable plain text, never fetched or automatically opened.
- Closing the reader clears only session navigation. Article/effect reading never changes needs, inventory, node metadata, protection, succession, food permission or persistent state. Submitted article text, source URLs, species IDs and page numbers are ignored; tabs and buttons use validated server-held state. No privileges, credentials, dynamic evaluation or runtime network access are added.
@@ -75,7 +102,7 @@ For an unavailable species, `kind = 'original_notes'`, `excerpt = false`, and `t
- Keep the warning that Wikipedia and game descriptions are **not identification, foraging, food preparation or medical advice**. Wikipedia can describe toxic species, traditional uses, disputed findings, or processing methods; copying its introduction does not endorse them or enable a game effect.
- Preserve Wikipedia attribution and [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/) when redistributing or adapting Wikipedia excerpts. Share adaptations under the applicable ShareAlike terms and describe modifications. This source-text license is distinct from the game's original code/art licenses. No images, page HTML or full article bodies are copied.
The shipped 78 introductions have a maximum of **3,417 Unicode code points**; **zero** required additional shortening. Extraction omits article bodies and uses MediaWiki's `exintro=1` / `explaintext=1`; whitespace is trimmed only at the ends. Future overlong introductions are cut on a paragraph, sentence, or word boundary without adding invented continuation text, and set `truncated = true`.
The shipped 98 introductions have a maximum of **3,417 Unicode code points**; **zero** required additional shortening. Extraction omits article bodies and uses MediaWiki's `exintro=1` / `explaintext=1`; whitespace is trimmed only at the ends. Future overlong introductions are cut on a paragraph, sentence, or word boundary without adding invented continuation text, and set `truncated = true`.
## What the real sources support about effects
@@ -98,7 +125,7 @@ Existing game niche thresholds, nutrient caps, timing, protection rules, edibili
[scripts/wiki-species.mjs](../scripts/wiki-species.mjs) uses Node.js 22+ built-ins only. Arguments are deliberately limited to exactly one of:
- `--refresh`: read the fixed botany catalogue, query all 80 Latin names, validate complete results, then replace the fixed Lua output. Explicit missing pages become original availability notes. Print exact source counts and batch bounds.
- `--refresh`: read the fixed botany catalogue, require exactly 100 literal rows, query all 100 Latin names, validate complete results, then replace the fixed Lua output. Explicit missing pages become original availability notes. Print exact source counts and batch bounds.
- `--check`: parse and validate the generated bundle and its agreement with the current catalogue **offline**. Print source counts and `network requests: 0`.
- `--help`: print maintenance usage, without reading articles or making requests.
@@ -107,7 +134,7 @@ Invoke Node with this script path and one of those flags. There are **no URL, ti
### Security and failure behavior
- Only `https://en.wikipedia.org/w/api.php` is fetched. Latin names go through a strict binomial allowlist and `URLSearchParams`, never string-interpolated query syntax. Queries contain only the public catalogue Latin names, not player names or private data. No credentials, API keys, cookies or authorization headers are used. The descriptive `LastHearthSpeciesBundle/1.0` user agent identifies this manual offline-bundle use.
- Scope: at most 80 titles, ten per batch, two concurrent batches. A complete normal refresh makes **eight API requests**. No search queries, crawl, pagination, automatic retries, external links, or per-player network activity.
- Scope: at most 100 records in fetcher/serializer/parser helpers, ten titles per batch, two concurrent batches. A complete normal refresh makes **ten API requests**. No search queries, crawl, pagination, automatic retries, external links, or per-player network activity.
- HTTP redirect mode is manual. At most two redirects per batch are accepted, only to the same allowlisted HTTPS origin, exact API path and unchanged query. Credentials, non-default ports, fragments, other hosts (including mobile subdomains), other paths and query changes are rejected. Article redirects are API data, not HTTP fetch destinations.
- Each batch has a **15-second total deadline**, including its redirects and response body. The complete run has a **90-second deadline**. Failed workers abort the remaining work. Responses are limited to **2 MiB of decoded response bytes**, checked against both Content-Length and streamed bytes; JSON MIME and valid UTF-8 are required. TLS validation is left enabled; no certificates or secrets are embedded or bypassed.
- Reject API errors/warnings, incomplete batches, missing response records, HTML/wikitext in introductions, disambiguation pages, namespace/language mismatches, invented aliases, title/canonical-URL mismatches, and invalid or inconsistent page/revision metadata. Only explicit `missing: true` for the exact species gets an original note. A timeout, HTTP error or validation failure is **not** turned into an availability note.
@@ -124,6 +151,8 @@ The focused reader run passed **19 reader/HUD checks**, **43 recipe/journal chec
[tests/wiki-species.test.mjs](../tests/wiki-species.test.mjs) runs independently with Node's test runner. It does not launch Luanti or use the full-engine suite.
The verified run has **21 passing tests, 0 failures, 0 real network requests, and 33 mocked transport requests**. Coverage includes URL/query injection, SSRF redirects, redirect limits, timeout/abort cleanup, MIME/UTF-8/size rejection, page/revision validation, source-title redirects, missing-page honesty, Unicode/boundary clipping, malicious-text Lua serialization, exactly eight mocked batches at concurrency two, offline CLI checks, and byte-for-byte cache preservation after an HTTP failure.
The verified focused Node run has **21 passing tests, 0 failures, 0 real network requests, and 35 mocked transport requests**. Coverage includes URL/query injection, SSRF redirects, redirect limits, timeout/abort cleanup, MIME/UTF-8/size rejection, page/revision validation, source-title redirects, missing-page honesty, Unicode/boundary clipping, malicious-text Lua serialization, exactly ten mocked batches at concurrency two, rejection of 99-row catalogues and 101-record fetch/serialized inputs, all twenty new exact identities, offline CLI checks, and byte-for-byte cache preservation after an HTTP failure. The separate approved `--refresh` above did use the network; tests and `--check` do not.
Snapshot assertions intentionally expect **78 Wikipedia excerpts + 2 original availability notes**. After a successful future refresh, review changed text, source identities, license/attribution, missing-page status and any effects claims; update the snapshot expectations and this document when coverage changes. Never replace a failing source with made-up text merely to make the count reach 80.
A separate isolated Fengari execution of the actual current botany source compared every runtime `list()` ID/Latin pair with the maintenance parser: **100/100 exact ordered matches**, empty stderr. Runtime group counts were **trees 13, shrubs 14, grasses 10, herbs 22, ferns/mosses 11, fungi 10, aquatic 10, lichens 10**; no equal-ten-per-category assumption was imposed. No catalogue or source-effects code was modified and no full-engine run was launched. Offline `--check` verified **100/100 species: 98 introductions, 2 original notes; network requests: 0**.
Snapshot assertions intentionally expect **98 Wikipedia excerpts (78 previous + 20 new) + 2 original availability notes**. After a successful future refresh, review changed text, source identities, license/attribution, missing-page status and any effects claims; update the snapshot expectations and this document when coverage changes. Never replace a failing source with made-up text merely to make the count reach 100.