Files
last-hearth/docs/fauna.md
T
2026-11-05 09:57:11 -05:00

510 lines
41 KiB
Markdown
Executable File

# Fauna: evidence, calendar time and integration contract
Reviewed 2026-11-04. Scope includes the catalogue, wildlife runtime, direct
in-game interaction panel and focused Lua tests. No engine run or visual-quality
acceptance is claimed by this change.
## Public interfaces
The catalogue is a factory: `dofile(modpath.."/fauna.lua")(hearth,api)`.
It returns `VERSION`, `SECONDS_PER_DAY`, `list()` / `catalog()` (ordered record
arrays), `get(id_or_entity)`, `kind(id_or_entity)`, `source(id)` (URL array),
`phase(id,born_at,utc)`, `breeding_window(id,month)` and
`can_breed(id,born_at,utc,sex,season?)`. Unknown IDs return nil or deny breeding.
All catalogue records and lists are defensive copies. Records expose `id`,
`entity`, `common`, `latin`, `source_url`, `wikipedia_url`, `sources`, `confidence`,
`profile` (unaltered lifecycle evidence), `foods`, `prey`, `medium`, `activity`,
`bounds`, `mesh`, `texture`, `clips`, `fps`, `frames`, `eye_height` and policy caps.
Main may construct `hearth.fauna` before wildlife. Otherwise wildlife loads the
fixed sibling factory via `api.get_modpath("hearth")`; no caller-supplied path or
saved asset name is accepted. The catalogue uses `hearth.lifecycle` or loads the
fixed sibling lifecycle module. Main should inject lifecycle so seeded cohort ages
use its `duration()` selection consistently. No network request occurs at runtime.
Wildlife returns `fauna`, `species` (legacy hare entity), `global_cap`,
`player_cap`, `local_cap`, `ai_budget`, `status()`. Status includes legacy
`total`, `hare`, `deer`, `fox`, plus a copied `counts` dictionary containing all
23 IDs, `species_count=23`, `actions`, `births`, `meals`, `grazed`, `dung`,
`deaths`, `pollinations`, `dispersals`, `detritus`, and the three caps.
It also exposes a defensive `recruitment` diagnostics copy: `interval=5`,
`scan_nodes=648`, `attempts`, `successes`, `scans`, `last_reason`, and `reasons`
(reason-to-count dictionary). The `/ecosystem` survey displays all species plus
admission attempts, successes and the latest outcome; it remains observation-only.
Reasons include `waiting`,
`invalid_player`, `global_cap`, `no_surface`, `observer_near`,
`blocked_or_unloaded`, `habitat_unloaded`, `no_active_food_match`,
`population_cap`, `unsafe_body`, `activation_rejected`, `admitted`,
`registry_unavailable`, `region_budget`, and `region_seeded`.
`status().residents` is a fresh diagnostics table containing `storage_ok`,
`regions`, `region_limit=4096`, `region_size=48`, `founders_per_region=4`, and
the persistent individual `counter`. Counts describe loaded residents, not the
entire unloaded population. Diagnostics do not expose mutable journal records.
## Field journal and ambient grouping
Right-clicking a live, pointable animal records that species in the observing
player's metadata under a versioned, bounded, canonical species-ID list. The
species guide marks recorded and not-yet-encountered identities; opening a
catalogue-only profile never unlocks an encounter. This is a private per-player
field-journal convenience, not a local census, achievement reward, or change to
the animal/world state. Invalid saved journal text fails closed and is never
overwritten. Active robins, blackbirds, blue tits and mallards also use a small,
local cohesion/separation bias when choosing wander direction. It is computed
from loaded same-species residents only—there are no persisted flock IDs,
unbounded entity scans, or forced spawn groups.
These are original adaptations of ambient grouping and encounter journaling
ideas visible in Animalia's public [bird behavior](https://github.com/ElCeejo/animalia/blob/main/mobs/song_bird.lua),
[AI](https://github.com/ElCeejo/animalia/blob/main/api/mob_ai.lua), and
[Libri](https://github.com/ElCeejo/animalia/blob/main/api/libri.lua) source.
Last Hearth does not include that mod's code, models, textures or audio.
## Runtime API integration
The managed package pins the MIT-licensed Creatura 0.2.10 release from ContentDB
release 34130; the downloaded archive SHA-256 and upstream commit are recorded
in [mods/creatura/UPSTREAM.md](../mods/creatura/UPSTREAM.md). Creatura supplies
animal-focused pathfinding, boid algorithms and its ABM spawn scheduler.
Last Hearth supplies species identities, original meshes/textures, habitat and
diet policy, caps, protected/provenance-aware admission, persistent resident
IDs, feeding transactions and player interactions. Creatura spawn callbacks do
not bypass Last Hearth's `on_activate` checks. Ambient ABMs are restricted to
common species, small groups, natural soil types and fixed per-species caps; no
drops, taming, combat or livestock systems are enabled. The bounded Last Hearth
recruitment path remains available as a fallback and does not award food when
vegetation serves only as an ambient habitat signal.
Engine API: entity/globalstep registration, connected players, loaded-only
`get_node_or_nil`, node definitions, node metadata, protection, `add_entity`,
`parse_json` / `write_json`, mod storage (`hearth.storage`, otherwise
`api.get_mod_storage()`), and normal ObjectRef position, velocity, yaw,
acceleration, armor and animation methods. Optional `api.now()` is an integer UTC
epoch test seam; otherwise `os.time()` is used. Climate uses
`hearth.climate_at(utc).season`; qualitative habitat seasons may be accelerated
by climate configuration, but animal ages and activity hours never are.
## Direct in-game interaction
Registered animal entities are natively pointable while retaining their
existing physical collision envelope. Luanti's normal object picking dispatches
right-clicks to `hearth.inspect_fauna(clicker, species_id, snapshot)`; this is
not a HUD raycast or a node-placement change. Wildlife verifies that the entity
is currently active and that the exact clicker is an online player with a
session, then passes a detached snapshot of calendar birth time, modeled
reserve, origin, persistence-ID availability and current rest/awake animation
observation. The callback is looked up at interaction time so wildlife does not
own formspec registration. The interface checks the online player and session
again, and escapes/bounds displayed catalogue and snapshot text. Species-guide
selection can also open a species-only profile; it is not a local animal census.
The panel reports Latin identity and source URLs, lifecycle phase and real
calendar age when available, currently modeled diet and prey, activity/sleep
and winter-rest policy, and whether reproduction is enabled for the profile or
disabled for incomplete evidence. Food reserve is explicitly labelled as a
coarse game policy, not biology. Persistent residency and current animation are
observations only; no position is displayed. A direct animal encounter adds one
species ID to the observing player's bounded field journal; catalogue browsing
does not. Neither action changes animal state, ecology, inventory or terrain.
Punching
continues to trigger flee movement; immortal armor and the lack of damage/drop
handlers prevent combat or item rewards. Collision and crafting/node placement
remain unchanged. Native mesh appearance and animation quality were not
visually verified in an engine session.
## Required succession transaction contract
These are **required transactional hooks**; the current succession supplies them.
Wildlife does not replace or bypass their shared budgets. Missing hooks or anything other than
literal boolean true gives no feeding credit and no ecological-success count.
Wildlife performs no direct vegetation/node mutation or inventory operation.
Main must repeat all loaded/protection/provenance checks inside each transaction.
Forage/deposit's entire 3x3 neighbourhood is guarded by wildlife before invocation.
| Hook | Exact required semantics |
| --- | --- |
| `habitat(pos)` | Loaded observation with `loaded`, `grass`, `cover`, `canopy`, `moisture`, `water`, `near_water`. Unknown/unloaded must fail recruitment. |
| `forage(pos) -> boolean` | Existing metadata-only natural browse debit, finite and seasonal, not inventory/crop consumption. |
| `deposit(pos) -> boolean` | Existing bounded metadata-only dung/nutrient receipt. One pending receipt per earned meal; no item or offline queue. |
| `pollinate(pos) -> boolean` | Atomically debit legitimate nectar from a mature, currently flowering natural plant and apply bounded pollination. Persist shared `succ_nectar_ready_at` before any callback; all bees compete for the same budget. Reject invalid timestamps. Use an explicit nectar replenishment policy; wildlife's 300-second inter-meal throttle is NOT evidence for floral replenishment. No seed generation. |
| `frugivore(pos, species_id) -> boolean` | Verify exact botany identity and fruiting season, then atomically debit the **same `botany_ready_at`** used by human `botany.harvest`. Set its existing annual (`365.2425 * 86400` seconds) resource deadline before callbacks. Never maintain a parallel animal-only berry budget; reject invalid/future readiness, nonnatural/planted nodes and immature shrubs. No inventory output. |
| `detritivore(pos) -> boolean` | Consume a finite unit of existing natural litter and transfer only conserved organic/mineral material. Reject empty substrate. Never an infinite soil fertility aura. |
| `granivore(pos, species_id) -> boolean, optional_cache_id` | Debit an existing finite seasonal seed/nut resource. True grants one meal; optional `"hazel"` or `"oak"` grants a **second separately debited viable nut**, not the eaten seed. No token if the second nut was unavailable. |
| `disperse_seed(pos, species_id) -> boolean` | Accept one immediately preceding, separately debited cache nut; check loaded natural viable destination and bounded seed metadata. Only squirrel hazel/oak caches invoke this hook. Consume authority once even if the destination fails (lost nut, never duplicated). No persistent token, offline planting, pollinator seed aura, or arbitrary new species. |
The cache hook must track immediate granivore authority in succession, rather than
trust arbitrary callers. Both source and destination are guarded; successful
consumption and successful caching are different counters. Seed-eating mice,
voles and birds are not automatically awarded dispersal. Fruit transport/gut
passage is not implemented and must not be presented as simulated.
## Time, provenance and deliberately unknown biology
**Six profiles now enable reproduction:** bank vole, wood mouse, blackbird, mallard, European hare and red fox. The sourced hare profile uses 365-day maturity, 42-day gestation, one leveret per litter and a 30-day care lock; its broad reported season is represented as Winter/Spring/Summer. The fox profile uses 304-day maturity, 53-day typical gestation, one pup per litter, and a conservative 300-day postpartum lock; its coarse breeding season is Winter. ADW reports 56-70 days of fox nursing/weaning, but the existing generic dependent-care loop cannot represent paternal provisioning or fox den care, so this species is not a complete family-behavior simulation.
Registration (`pending=false` for all 23) is independent
of evidence completeness. This is not whole-ecosystem true-life certification.
The following pages were retrieved on 2026-11-03; ranges are original factual
summaries, not bundled article text. Runtime uses conservative upper development
and maturity endpoints and the lower sourced litter/clutch count.
| Species | Maturity | Development to birth/hatch | Count | Sources and limitations |
| --- | --- | --- | --- | --- |
| bank vole | 42-56 d sex envelope; runtime 56 d for both | 17-24 d gestation; runtime 24 d | 3-5, runtime 3 | [ADW](https://animaldiversity.org/accounts/Myodes_glareolus/) gives 17-24 d, 20-25 d weaning, late April-September; [Woodland Trust](https://www.woodlandtrust.org.uk/trees-woods-and-wildlife/animals/mammals/bank-vole/) supplies conservative 6/8-week maturity; [Wildlife Trusts](https://www.wildlifetrusts.org/wildlife-explorer/mammals/bank-vole) supplies the chosen 3-5 count. ADW reports a wider 1-10, typically 4-8; these are not silently merged. |
| wood mouse | 65-71 d; runtime 71 d | 21-26 d gestation; runtime 26 d | 4-8, runtime 4 | [ADW](https://animaldiversity.org/accounts/Apodemus_sylvaticus/) gives maturity, gestation and 21 d weaning, but 4-7 young; retained 4-8 is from [Wildlife Trusts](https://www.wildlifetrusts.org/wildlife-explorer/mammals/wood-mouse). [Wikipedia](https://en.wikipedia.org/wiki/Wood_mouse) reports February-October season and 23-27 d gestation, differing from ADW. |
| blackbird | about one year | 13-14 d incubation; runtime 14 d | 3-4, runtime 3 | [ADW](https://animaldiversity.org/accounts/Turdus_merula/) gives first breeding at one year, 13-day prose/14-day summary and 13-14 d leaving nest. [RSPB](https://www.rspb.org.uk/birds-and-wildlife/blackbird) supplies clutch/nesting window. Fledging is not full independence. |
| mallard | 365 d both sexes | 26-28 d incubation; runtime 28 d | 9-13, runtime 9 | [ADW](https://animaldiversity.org/accounts/Anas_platyrhynchos/) gives these values; [Wikipedia](https://en.wikipedia.org/wiki/Mallard) gives 50-60 d to flight and spring nesting. Unknown lifespan does not prevent breeding. |
| European hare | 236-365 d; runtime 365 d | 30-42 d gestation; runtime 42 d | 1-8 leverets, runtime 1 | [ADW](https://animaldiversity.org/accounts/Lepus_europaeus/) reports maturity at 8 months-1 year, one-month weaning, 30-42 d gestation and 1-8 per litter; winter through midsummer breeding. One-month care lock is a conservative policy. |
| red fox | about 304 d; runtime 304 d | 51-53 d typical gestation; runtime 53 d | 1-9 in ADW summary, runtime 1 | [ADW](https://animaldiversity.org/accounts/Vulpes_vulpes/) reports 10-month maturity, winter mating in central-range populations, 51-53 d typical gestation and 56-70 d nursing/weaning. Its prose says 1-13 while its summary table says 1-9; the narrower table range is retained. A 300-day postpartum lock approximates its once-yearly seasonal cycle; this is policy. |
Breeding requires same-species female and male within two nodes, both mature,
safe, recently fed (within twice their feeding throttle), reserve at least 0.7,
and loaded food-bearing habitat. Conception spends 0.2 reserve from each parent;
each delivered young spends another 0.1 from the mother and starts with 0.1.
These are explicit normalized energy policies, **not biological calorimetry**.
Only successful succession transactions earn reserve. There is no feeding-count
shortcut to maturity, free fertility command, item reward or player attack.
`hearth.climate_at(utc).season` (or an explicitly supplied season) determines the
hemisphere-aware season gate: Spring/Summer for the four original profiles,
Winter/Spring/Summer for hare, and Winter for fox. Northern reference months remain research
observations, not a simultaneous northern-month veto on southern spring. These
coarse season policies omit some legitimate early-autumn breeding;
it is not exact local phenology. Missing climate denies new conception. Calendar
age and due times always use real epoch seconds, never climate-speed multipliers.
Pregnancy and incubation use a common persisted deadline field; eggs are a
bounded maternal brood state, **not mammalian pregnancy or separate nest nodes**.
Egg laying, nest construction, exact incubation attendance and clutch failure
are not simulated. Dependent young rest rather than hunt/browse as adults;
nearby loaded mothers transfer 0.05 reserve at the ordinary feeding cadence.
This is coarse care accounting, not milk chemistry or a species-specific chick
diet. Maternal postpartum locks are 25 d (vole), 21 d (mouse), 42 d (blackbird),
81 d (mallard), 30 d (hare) and 300 d (fox) after the last admitted young. Bird locks deliberately include an
extra 21 d beyond the conservative dependency/fledging allowance. They do not
claim measured inter-clutch intervals. Assets still use the authored species
mesh, not visually distinct baby models.
**Seventeen profiles stay reproduction-disabled**, including three legacy slots.
Blue tit now has [BTO](https://www.bto.org/understanding-birds/articles/blue-tit-diary)
8-10 typical eggs, about 14 d incubation and 18-21 d fledging; first breeding is
described as the next spring, not an accepted exact day threshold, and represented
caterpillar provisioning is missing. ADW's Cyanistes URL was missing and its
older Parus URL contained taxonomy only; neither validates numerical overrides.
[Common frog](https://en.wikipedia.org/wiki/Common_frog) adds about 3-year maturity
and 14-21 d incubation, but aquatic eggs/tadpoles and their food remain absent.
[Brown trout](https://en.wikipedia.org/wiki/Brown_trout) needs female mass for its
approximately 2000 eggs/kg, a gravel redd and temperature-dependent development.
[Bumblebee](https://en.wikipedia.org/wiki/Bombus_terrestris) requires queen/worker/
male castes and colony care; a single litter timer would be misleading. Rabbit
maturity, squirrel conception season, roe deer/stoat implantation, other mammal
profiles, robin/barn owl care, newt larvae and worm cocoons remain incomplete.
No missing values are filled with guesses. Lifespan averages never trigger death.
One-time regional founders represent existing wild individuals, **not reproduction**.
Where maturity is sourced, the estimated initial age uses its upper endpoint;
`born_at=utc-estimated_age_days*86400`, `origin="established"` explicitly labels
the estimate. Unknown maturity has no invented age offset and still remains an
established individual, not a purported newborn. `origin="born"` marks actual
admitted young with `born_at=utc` at delivery, including delayed admission after
an overdue pregnancy; it never creates an adult-aged catch-up cohort.
`self.id` remains an in-memory scheduling serial. `state.resident_id` is the
separate durable world-local positive integer allocated from mod storage;
`state.founder_region` identifies the founder's geographical cell, or is empty
for births and legacy-ID migration. Sex, selection seed, food reserve, birth
epoch and reproductive state survive normal unloading and restart. Position is
saved by the engine's static-object system, not copied into a second registry.
Feeding throttles (nectar five minutes, predators two hours, other plant food one
hour), movement speeds except earthworm, and normalized two-day energy reserves
are **coarse simulation policies**, not sourced metabolic measurements. Unknown
starvation durations are false: hunger can accumulate over hours/days but cannot
justify an invented death threshold. Rabbit is the sole enabled starvation
case: the fetched European rabbit account reports winter survival without food
of about 2-8 days; the conservative upper eight-day bound is used, counting
only represented loaded hunger (`hunger_seconds`), never an unloaded absence. This is
not a veterinary prediction for an individual. No free food appears because a
predator lacks prey. There are no modeled insect-larva, mayfly, beetle, parasite,
egg or nestling populations to feed on. Thus adult trout currently have no
supported live-prey recruitment resource; saved trout swim and remain otter prey
without pretending an unimplemented invertebrate biomass exists.
## Persistence and bounds
`static_save=true`. Static state is version-1 JSON, at most 2048 bytes, with only
`version`, `species`, `born_at`, `origin`, `sex`, `foodreserve`, `nextfeed`,
`pregnancy_until`, `last_seen`, `seed`, `last_meal`, `dung_pending`, plus
`conception_at`, `litter_total`, `litter_remaining`, `litter_delivered`,
`nextbreed`, `last_birth_at`, `parent_seed`, `parent_born_at`, `resident_id`,
`founder_region`, `hunger_seconds`. No deserialize,
Lua evaluation, arbitrary asset names or paths. Exact entity/species match,
finite numeric types/ranges and coherent nonfuture observation/birth/meal clocks
are mandatory. Flat/nonnested input is checked before silent JSON decoding.
Pregnancies require an enabled female profile, mature conception, exact sourced
maximum development interval, coherent bounded integer litter counts, and a
deadline no further ahead than that interval. Overdue deadlines remain valid.
The old version-1 empty reproductive state migrates to zero counters; old nonzero
pregnancies without the new schema are refused. Next-feed deadlines are bounded to one day ahead; future birth or
observation data is rejected, never used for credit. Failed JSON encoding emits
an invalid sentinel rather than silently making a fresh cohort next load.
Validated **existing residents always restore**, even above species/global/local/
player caps, with no connected-player API, or on newly claimed, blocked,
foodless, `nil`/`ignore` unloaded terrain. Positive native `dtime_s` is expected
for restoration and is accepted. No habitat or collision read may delete a
validated existing resident merely because its surroundings changed. Invalid
snapshots, unknown fields/species, incoherent clocks or out-of-world coordinates
are still rejected, with bounded reason-only warnings (no raw payload logging).
Movement and ecological transactions stop safely inside new claims, ambiguous
claims, external protection or unknown/unsafe collision terrain. An animal on
still-safe but depleted ground can wander and become hungry rather than vanish.
There is no teleport/terrain-repair escape for an animal trapped by construction.
Deactivation forgets **live counts only**, idempotently; it never records a
death or removes founder membership. Nothing deletes an existing animal to
free admission slots. Dormant mapblock animals stay in the engine save and can
return above the new-admission caps. Births and new founders, unlike restores,
still require all current safety, habitat and cap checks. There is no 900-second
lifetime or walk-away despawn/replenishment path.
Offline **calendar ages/deadlines** advance from saved epochs, but unloaded AI
is frozen, not a whole-world ecological simulation. There are no replayed
offline meals, mating cycles, founder admissions or dung/caching queues.
An existing overdue brood is reconciled on budgeted AI after a player returns:
at most one newborn per attempt, no more than its single stored litter total.
Species/global/local/player caps, safe loaded positions, current habitat and
maternal energy still apply. Full caps delay the original due time without
redating; remaining/delivered counts survive normal save/reload. Failed admission
does not spend a child; callback reservations and activation acknowledgement
prevent synchronous reentry duplication. Once complete, the brood clears and
postpartum lock prevents repeated deliveries. This is normal-save idempotence,
**not a cross-mapblock crash-atomic transaction or authenticated save format**.
Server-local static data is not exposed as client/admin fertility input. Schema
validation rejects giant/incoherent payloads but cannot authenticate a coherently
rewritten world save; operators must protect world files. No such bypass API is added.
Energy/hunger work on each safe loaded observation is bounded to 60 seconds;
restoration preserves reserve and accumulated hunger, resets the observation
clock and clears the pending dung attempt. A successful meal or maternal
feeding resets loaded hunger. Legacy snapshots start hunger at zero because
their historical loaded/unloaded intervals cannot be reconstructed. Unsafe or
player-absent AI turns freeze energy/hunger. No force-loading or emergence.
### One-time, geographically bounded founder registry
The separate mod-storage key is **`wildlife_residents_v1`**. This does not change
the game's world-schema version. Its flat JSON envelope has `version=1`,
`counter` (last allocated individual ID), and sparse `r_<x>_<z>` fields.
Cell coordinates are `floor(world_x/48)`, `floor(world_z/48)`, including negatives;
they do not depend on player, session, Y, current population or visit count.
Each region value is a canonical bounded string:
`attempts/last_attempt_utc/resident_id=species;resident_id=species;...`.
Both the decoder and encoder enforce the 1,048,576-byte registry ceiling;
each region value is at most 256 bytes with at most **four founder memberships**.
The decoder requires exact version, known species, valid bounded cell keys,
finite integral clocks/counter/IDs, unique founder IDs and no extra fields.
Nested/deep JSON is rejected before parsing; no code evaluation, assets, paths,
credentials or client-provided allocation authority are stored.
At most **4096 region records** can ever be admitted automatically. Records
are never evicted, reset on return, silently truncated or recycled after death.
New regions beyond this permanent budget are refused; existing records and
saved animals remain intact. Attempts (saturating at one billion) and last UTC
are persisted even for a loaded search that has no surface, unavailable food,
or unloaded/invalid candidates; these attempts do **not** fill founder quota.
An incomplete cell remains retryable on later valid observations, with no
timeout that marks an empty/unloaded area permanently populated. A full cell
never fills a dead, eaten, migrated-away or currently unloaded animal's slot.
Different eligible species may share its four slots; their IDs and types are
retained permanently, not inferred from live counts. This is a one-time founder
quota, not a continuously restored carrying-capacity target. Natural births
remain independently funded by the existing calendar/food/cap rules and do not
spend or refund founder slots.
Membership and monotonic ID allocation are written/read-verified **before**
the new animal is acknowledged. Storage read/write failure, silent dropped
writes, invalid JSON/version, duplicate/unknown membership, or any exceeded
bound disables all new admissions (including births), without deleting validated
existing residents. Missing storage also disables new admissions. A known saved
ID above a missing/rolled-back counter fails closed instead of reusing its ID.
Legacy snapshots without ID fields receive an ID and empty `founder_region`
when storage is healthy; with failed storage they remain valid residents without
an allocated ID, rather than being destroyed. They can migrate on a later restore
after operator repair. Never clear this key to make animals reappear: restore
world/mod-storage backups together. A process/storage crash after reservation
can conservatively spend a founder slot or burn an ID without creating an animal;
there is no cross-mapblock crash-atomic population transaction or automatic refill.
New-admission global cap is 64; player-neighbourhood cap 16 within 48 nodes;
local cap 12 within 16 nodes. Per-species caps range 2-8. Overlapping player
neighbourhoods are all checked for new founders/births only, never movement or
restoration. Loaded counts can exceed these limits after restoration; this
delays further admissions without erasing any resident. AI and founder searches share 24 actions/second,
maximum one second of accrued work; entities are visited in serial round-robin
order. Recruitment spends one action every five active seconds, with no credit
banked while players are absent. It rotates players and eight search patches,
queries one 9x9x8 box through `find_nodes_in_area_under_air` (648 cells maximum),
and checks one round-robin surface candidate per attempt. This is at most 12
queries / 7,776 queried cells per active minute, not a whole-map scan. Habitat,
body-envelope and ordinary AI observations are additional bounded work, not
included in that terrain-query cell count. No query may emerge unloaded blocks.
An integration without this search API reports `no_surface`, not a guessed Y.
Candidates lie 12-24 horizontal nodes from the selected observer; any observer
within eight nodes vetoes admission. Ground/plant surfaces set the body base
half a node above actual support, not at the player's Y. Water surfaces retain
their own water-cell Y and use the stand above water for succession observations.
The fixed vertical search band is player Y minus four through plus three;
distant cliffs outside this band wait for a closer observer.
One plant-food observation and one succession habitat observation are shared
across cheap rotating catalogue matches. Only currently active, habitat/food-fit,
uncapped species receive body-safety/admission checks. There are no 23 separate
terrain scans or a forced 11.5-minute wait for the next eligible species.
Daylight flowering yarrow can admit a bee, mixed understory a bank vole; nocturnal species
remain nocturnal and predators still require represented fruit or actual prey.
Qualitative herb seeding seasons are not an implemented food budget: only
oak/hazel nuts are recognized as seeds, matching succession's `granivore` debit.
Founder admission does not call `can_breed`, require a completed reproductive profile,
or fabricate an age/maturity threshold for unknown biology.
Unadopted, unmarked, supported worldgen understory is collision-passable without
pretending it was already adopted. At a recruitment candidate, at most nine
ground-level cells use guarded `diversity.bootstrap` (when available). The three
legacy meadow-grass/fern/wildflower sprites receive only `succ_natural` metadata
under the same loaded, natural-support and provenance checks. This closes the
gap between succession's 12-node adoption ring and the wildlife search ring.
No botanical birthday/profile, forage ration, inventory item or plant node is
created. Unknown placement metadata, named planter markers, claims, ambiguous
claims and external protection deny adoption. Botany's presence does not hide
legacy grass/fern browse. Every subsequent meal still requires the existing
finite succession transaction; merely discovering or adopting a plant grants no
nutrition. Existing saved animals activate before the first observer joins,
without bootstrap, safe/room rejection or a current-food requirement; unsafe
terrain freezes subsequent movement/transactions rather than destroying them.
Founders are initialized only as loaded habitat is explored near an observer;
unexplored regions have not yet been instantiated. This unavoidable lazy
initialization is not recurring immigration when walking around a seeded region.
There is no startup world-wide spawn, force-loading or offline execution.
Per-frame safety/velocity checks are bounded per loaded entity and do not count
as AI decisions. Restoration may exceed 64 loaded objects; the shared AI action
ceiling remains 24/second, but per-frame callbacks/list sorting are not a measured
constant CPU bound for an arbitrarily large restored population.
### Absent-animal diagnosis and focused regression
Before this correction, a single hardcoded candidate at player Y was tried for
one species every 30 seconds. All 23 species therefore took 690 seconds (11.5
minutes) to revisit. Slopes failed body support, and unadopted sprites both
blocked clearance and failed food recognition outside succession's adoption
ring. With botany loaded, legacy meadow grass/fern also lost the fallback browse
path. These were admission/resource blockers, not a missing adult-age privilege:
this runtime never gated immigration on known maturity or `can_breed`. The old
danger comparison used squared distance 16 (four nodes); it now uses 64 (eight).
The focused wildlife suite now has 57 named checks. It adds repeated physics steps across AI intervals, approach to reachable food, fine-grained collision sweep, solar activity and dormancy, danger/hunger while resting, winter browse-mode negotiation, and sourced hare/fox reproductive timing.
## Movement and art
Every fixed ID uses `hearth_fauna_<id>.b3d` and `hearth_fauna_<id>.png`.
Five actual ObjectRef animation calls select idle 0-19, locomotion 20-39,
feed 40-59, flight/swim 60-79, rest 80-99, at 24 fps with 0.15-second blend.
The authored asset has 100 frames. Bounds were obtained from `faunaBounds()` in
the existing art generator (10 model units per node), including long fox tails,
squirrel tail height, bird wings and antlers. Eye heights have a 0.15 minimum.
Collision is based on those measured bind bounds; safety uses a yaw-independent
envelope and animation margin, checking bottom, middle and top, source,
destination and a swept path sampled at no more than 0.2 nodes (at most 20
intervals for a four-node segment). No `set_pos` teleport movement.
Velocity ramps at at most 2 nodes/second squared up to a 1.3 nodes/second ceiling;
each command has a 2.5-second lease, exceeding the two-second AI interval.
Safety stops may be abrupt. Land,
low flight, submerged swimming and moist-land invertebrate corridors differ;
amphibians/otters/mallards may inhabit either land or water but **shore transitions
are deliberately refused** until swept bank-ramp traversal is implemented.
Flight can move vertically within a three-node natural-ground corridor.
Unloaded, claimed, ambiguous, protected, building, unsupported and wrong-medium
samples stop movement. This is conservative local movement, not full navigation,
arboreal climbing, digging, seasonal migration or fluid dynamics. Gravity is held
at zero inside these validated corridors to avoid uncontrolled cliff falls.
The earthworm surface speed is the reported 20 metres/hour, not a mammal sprint.
Species activity differs: local solar day/night schedules, twilight activity,
winddown/wakeup transitions, short rest windows for flexible activity profiles,
and winter dormancy for hedgehogs, frogs and newts. Danger is processed before
rest and loaded hunger continues during sleep; dormancy never removes an animal.
Resource search checks a fixed 5x5 horizontal area and follows a reachable food
candidate rather than requiring it beside the next AI tick. Winter browse accepts
only a non-toxic tagged tree/shrub and never implies human edibility. Wildlife
passes `winter_browse` to the shared forage hook, but the current succession
implementation does not accept that mode; winter twig/stem debiting is therefore
not active until a separately scoped succession change. Ordinary shared browse
continues to use its existing seven-day plant cooldown. Also represented are
danger flight and hedgehog stillness, alert pauses, nectar visits,
fruit feeding, nuts/caching, litter consumption and actual finite prey pursuit.
The source accounts describe many additional behaviors; descriptions are not
claims that burrows, dreys, antler shedding, caste systems or parenting are coded.
Art quality requires separate native-engine animation/visual acceptance.
## Research register and implemented nutritional web
Fetched Wikipedia identity/diet accounts (first eight plus earthworm/deer), and
Wildlife Trust/RSPB accounts for the remaining rows, on 2026-11-03. All Wikipedia
URLs are explicit identity links; generic deer is **Cervidae**, not a silently
chosen Latin binomial. Bank vole retains the lifecycle identity *Myodes glareolus*
(synonym *Clethrionomys glareolus* on the retrieved Wikipedia page). Prose below
is original summary; no source media or article text is bundled.
| ID | Identity / Wikipedia URL | Reviewed nutrition and represented behavior |
| --- | --- | --- |
| hare | [Lepus europaeus](https://en.wikipedia.org/wiki/Lepus_europaeus) | Grass/herbs, surface forms, nocturnal escape; represented browse and fox prey. |
| deer | [Cervidae, unidentified legacy deer](https://en.wikipedia.org/wiki/Deer) | Family-level foliage browsing only; no species timing asserted. |
| fox | [Vulpes vulpes](https://en.wikipedia.org/wiki/Vulpes_vulpes) | Hare/rabbit/vole/mouse/squirrel/worm/frog prey, seasonal berries; mostly nocturnal. |
| rabbit | [Oryctolagus cuniculus](https://en.wikipedia.org/wiki/Oryctolagus_cuniculus) | Grass/leaves; fox and stoat prey; no fictitious warren reproduction. |
| red_squirrel | [Sciurus vulgaris](https://en.wikipedia.org/wiki/Sciurus_vulgaris) | Seeds/nuts/fruit; diurnal, canopy-dependent establishment; separately funded oak/hazel cache. |
| bank_vole | [Myodes glareolus](https://en.wikipedia.org/wiki/Myodes_glareolus) | Leaves/seeds/fruit, needs cover; fox/stoat/weasel/owl prey. |
| wood_mouse | [Apodemus sylvaticus](https://en.wikipedia.org/wiki/Apodemus_sylvaticus) | Seeds/fruit and nocturnal covered movement; fox/stoat/weasel/owl prey. |
| hedgehog | [Erinaceus europaeus](https://en.wikipedia.org/wiki/Erinaceus_europaeus) | Finite earthworm prey, nocturnal/winter rest; badger prey. |
| badger | [Meles meles](https://en.wikipedia.org/wiki/Meles_meles) | Worms, rodents, hedgehogs, fruit; nocturnal. No adult rabbit edge: account emphasizes kittens. |
| roe_deer | [Capreolus capreolus](https://en.wikipedia.org/wiki/Capreolus_capreolus) | [Wildlife Trust](https://www.wildlifetrusts.org/wildlife-explorer/mammals/roe-deer): buds/leaves/herbs/grass; delayed implantation not fabricated. |
| stoat | [Mustela erminea](https://en.wikipedia.org/wiki/Mustela_erminea) | [Wildlife Trust](https://www.wildlifetrusts.org/wildlife-explorer/mammals/stoat): rabbit and small rodents; day/night hunting. |
| weasel | [Mustela nivalis](https://en.wikipedia.org/wiki/Mustela_nivalis) | [Wildlife Trust](https://www.wildlifetrusts.org/wildlife-explorer/mammals/weasel): vole/mouse/small birds, low running. |
| otter | [Lutra lutra](https://en.wikipedia.org/wiki/Lutra_lutra) | [Wildlife Trust](https://www.wildlifetrusts.org/wildlife-explorer/mammals/european-otter): salmonids/frogs/newts; aquatic pursuit. |
| robin | [Erithacus rubecula](https://en.wikipedia.org/wiki/Erithacus_rubecula) | [RSPB](https://www.rspb.org.uk/birds-and-wildlife/robin): earthworms, seeds, fruit; hopping/flight. |
| blackbird | [Turdus merula](https://en.wikipedia.org/wiki/Turdus_merula) | [RSPB](https://www.rspb.org.uk/birds-and-wildlife/blackbird): earthworms and seasonal fruit; ground feeding. |
| blue_tit | [Cyanistes caeruleus](https://en.wikipedia.org/wiki/Cyanistes_caeruleus) | [RSPB](https://www.rspb.org.uk/birds-and-wildlife/blue-tit): seeds/nuts/berries; caterpillars are described but absent from simulated food supply. |
| barn_owl | [Tyto alba](https://en.wikipedia.org/wiki/Tyto_alba) | [RSPB](https://www.rspb.org.uk/birds-and-wildlife/barn-owl): finite voles/mice, low hunting flight; no adult-rabbit edge. |
| mallard | [Anas platyrhynchos](https://en.wikipedia.org/wiki/Anas_platyrhynchos) | [RSPB](https://www.rspb.org.uk/birds-and-wildlife/mallard): seeds/berries/plants; water-associated. |
| common_frog | [Rana temporaria](https://en.wikipedia.org/wiki/Rana_temporaria) | [Wildlife Trust](https://www.wildlifetrusts.org/wildlife-explorer/amphibians/common-frog): invertebrates; only registered earthworms modeled; moist habitat/winter shelter. |
| smooth_newt | [Lissotriton vulgaris](https://en.wikipedia.org/wiki/Lissotriton_vulgaris) | [Wildlife Trust](https://www.wildlifetrusts.org/wildlife-explorer/amphibians/smooth-newt): land worms, nocturnal moist habitat; aquatic prey stages unimplemented. |
| brown_trout | [Salmo trutta](https://en.wikipedia.org/wiki/Salmo_trutta) | [Wildlife Trust](https://www.wildlifetrusts.org/wildlife-explorer/freshwater-fish/brown-trout): larvae/small fish/flying insects; no phantom biomass, saved trout are finite otter prey. |
| bumblebee | [Bombus terrestris](https://en.wikipedia.org/wiki/Bombus_terrestris) | [Wildlife Trust](https://www.wildlifetrusts.org/wildlife-explorer/invertebrates/bees-and-wasps/buff-tailed-bumblebee): legitimate nectar/pollen at active flowers; shared pollination/nectar transaction, not seed dispersal. |
| earthworm | [Lumbricus terrestris](https://en.wikipedia.org/wiki/Lumbricus_terrestris) | Natural dead leaves/mineral soil; moist nocturnal surface motion, finite litter debit. Wild lifespan unknown; captive six-year record is not a death deadline. |
Lifecycle's separately attributed numerical references also include
[ADW rabbit](https://animaldiversity.org/accounts/Oryctolagus_cuniculus/),
[ADW squirrel](https://animaldiversity.org/accounts/Sciurus_vulgaris/),
[ADW wood mouse](https://animaldiversity.org/accounts/Apodemus_sylvaticus/) and
[Woodland Trust bank vole](https://www.woodlandtrust.org.uk/trees-woods-and-wildlife/animals/mammals/bank-vole/).
Those evidence values retain field-level confidence; unsupported fields stay unknown.
## Focused acceptance
Standalone catalogue and wildlife tests use injected clocks and strict expected
named-test totals; no native engine, background game instance or offline event
replay is involved. They cover catalogue identity/evidence/copies, real-day age,
unknown breeding denial, seasons, JSON hostile payloads and roundtrip, all caps,
startup restore before players, all modeled trophic classes, single-use prey,
feeding cooldowns, protected source/destination stencils, shared floral/fruit
budgets, finite litter/nut authority, velocity bounds/no teleport, runtime
animation calls, cliff/water/unloaded refusal, and scheduler work caps.
The wildlife suite now defines **57 named checks**, including the movement,
activity, dormancy, browse-mode and sourced breeding regressions. These changes
were not executed in this pass. No native engine, full-repository test
run, real-world save or art files are changed. These tests validate mocked
runtime contracts, not native mapblock persistence, rendered young animals,
engine crash recovery or biological completeness; native integration remains
the main agent's responsibility.