32 KiB
Executable File
Botany: 80 temperate taxa and integration contract
Scope and evidence
The catalogue in mods/hearth/botany.lua has 80 distinct real species, partitioned into eight ordered groups of ten. It represents a north-west/central European temperate landscape mosaic: deciduous woods, conifer woods, hedgerows, acid heath, wet meadow, bog and freshwater margins. It does not imply that all species grow together in one patch, or that all are native to every British locality. Norway spruce is native to continental northern/central Europe and widely planted in Britain. Hazel is counted only among trees; heather only among herbs; rushes and reedmace only among grasses/sedges. Lichens are lichen-forming fungi but have their own disjoint gameplay category, not a second count in fungi.
Taxonomic/reference authorities for maintaining these names and broad habitats:
- P: BSBI/UKCEH Plant Atlas 2020 for vascular-plant regional distributions, habitat and nomenclature; Kew Plants of the World Online for name/synonym checks. Kew blocked automated access during this implementation; no claim of an automated 80-record authority audit is made.
- T: Woodland Trust British tree accounts and plant accounts, complementary common names and woodland niches.
- W: The Wildlife Trusts wildflower accounts, including freshwater plants.
- M: British Bryological Society, Mosses and Liverworts of Britain and Ireland: A Field Guide (2010), and Atlas of British & Irish Bryophytes (2014), for the five moss names/niches. Online BBS access also blocked automated retrieval; these are bibliographic authorities, not downloaded records.
- F: British Mycological Society English names, Index Fungorum, and First Nature fungal accounts. Particularly fly agaric for root-host associations, birch polypore for birch/deadwood associations and its modern name, and wood blewit for litter decomposition and late fruiting.
- L: British Lichen Society species accounts and maps and its Lichens of Great Britain and Ireland. Names and species boundaries evolve; common lichen names are not universally standardized.
The numeric light/moisture/pH/depth windows below are explicit game approximations, not measured ecological tolerances, identification keys, conservation advice or a scientific simulation. The catalogue selects named species rather than inventing generic “magic herbs”. Rubus plicatus is one real blackberry species, not the Rubus fruticosus aggregate counted as a species. Meadow fescue Schedonorus pratensis is also encountered as Festuca pratensis / Lolium pratense. Wood blewit Collybia nuda is widely recorded as Lepista nuda / Clitocybe nuda. Birch polypore Fomitopsis betulina replaces the familiar Piptoporus betulinus. These synonyms are not extra entries.
No real-world foraging, medicinal or consumption claims are provided. Only three fictional bush outputs use the existing game item hearth:berries. This is a gameplay simplification, not a statement that a wild plant or lookalike is safe. Every fungus, herb, tree and lichen has food=false; toxic/stinging examples are flagged but toxic=false is not a safety certification. browse describes wildlife relationships, not player edibility. No new food items, recipes, poisoning system or damage to player plants are registered.
Exact ID manifest (art, trees and ecology handoff)
id is the canonical catalogue key. Every non-tree node is exactly hearth:<id>. Every tree's initial node is hearth:<id>_seedling; tree stages/resources belong to the diversity/resources owner. Do not create a second generic berry bush or alias a generic patch into this count. Existing generic berry_bush, fern, wildflowers and meadow_grass remain outside the 80.
Owner flags: E = existing node, never registered here; D = tree diversity owner, never registered here; B = new botany-owned node. The 13 existing mappings are retained verbatim: five trees plus clover, nettle, heather, bluebell, sedge, bulrush, moss and lichen. “Sedge”, “moss” and “lichen” receive a specific catalogue interpretation; their old IDs do not change.
Art contract for all 80: hearth_botany_<id>.png. This module uses that exact tile for each of its 62 new understory nodes. Trees use species bark cubes and full-block leaf crowns supplied by diversity/terrain; no seasonal tree mesh is introduced on a cube. Seasonal copying preserves bark/end-grain faces, facedir, callbacks and drops; foliage gets its own species-season texture. Assets and real-engine visual validation remain the art/main integration owners' responsibility.
trees (10; P/T)
| id | Common name | Scientific name | Owner | Habitat emphasis |
|---|---|---|---|---|
| oak | Pedunculate oak | Quercus robur | E/D | Mesic woodland; ectomycorrhizal roots |
| birch | Silver birch | Betula pendula | E/D | Light acid pioneer woods |
| pine | Scots pine | Pinus sylvestris | E/D | Open acid woods; resin |
| willow | White willow | Salix alba | E/D | Wet alluvial woods; spring flowers |
| alder | Common alder | Alnus glutinosa | E/D | Wet woods; Frankia-associated nitrogen fixation |
| beech | European beech | Fagus sylvatica | D | Well-drained woodland, avoiding saturation |
| aspen | European aspen | Populus tremula | D | Light woodland gaps |
| rowan | Rowan | Sorbus aucuparia | D | Cool acid woodland/edges; flowers |
| hazel | Common hazel | Corylus avellana | D | Woodland understorey; ectomycorrhiza |
| spruce | Norway spruce | Picea abies | D | Moist acid conifer woods; resin |
shrubs (10; P/T)
| id | Common name | Scientific name | Owner | Habitat emphasis |
|---|---|---|---|---|
| bilberry | Bilberry | Vaccinium myrtillus | B | Acid heath/woodland; ericoid, not ectomycorrhizal |
| blackberry | Pleated blackberry | Rubus plicatus | B | Hedgerows/wood edges |
| raspberry | Red raspberry | Rubus idaeus | B | Woodland clearings |
| elder | Black elder | Sambucus nigra | B | Hedgerows; no game food |
| blackthorn | Blackthorn | Prunus spinosa | B | Thorny hedges; spring flowers |
| hawthorn | Common hawthorn | Crataegus monogyna | B | Hedgerows; spring flowers |
| dog_rose | Dog rose | Rosa canina | B | Open scrub; summer pollen |
| holly | European holly | Ilex aquifolium | B | Evergreen woodland cover; no game food |
| juniper | Common juniper | Juniperus communis | B | Open dry heath/scrub; resin |
| guelder_rose | Guelder rose | Viburnum opulus | B | Damp hedges/wet edges; no game food |
grasses (10; includes sedges, rushes and reedmace; P)
| id | Common name | Scientific name | Owner | Habitat emphasis |
|---|---|---|---|---|
| sedge | Greater tussock-sedge | Carex paniculata | E | Wet bank tussocks |
| bulrush | Bulrush (great reedmace) | Typha latifolia | E | Reedbed margin; bank-cell approximation |
| meadow_fescue | Meadow fescue | Schedonorus pratensis | B | Moist neutral grassland |
| cocksfoot | Cock's-foot | Dactylis glomerata | B | Mesic meadow/edge |
| timothy | Timothy | Phleum pratense | B | Moist meadow |
| sweet_vernal_grass | Sweet vernal-grass | Anthoxanthum odoratum | B | Acid grassland |
| yorkshire_fog | Yorkshire-fog | Holcus lanatus | B | Mesic grassland |
| tufted_hairgrass | Tufted hair-grass | Deschampsia cespitosa | B | Wet meadow tussocks |
| common_reed | Common reed | Phragmites australis | B | Wet banks/reedbed edges |
| soft_rush | Soft rush | Juncus effusus | B | Wet pasture/bog margin |
herbs (10; P/T/W)
| id | Common name | Scientific name | Owner | Habitat emphasis |
|---|---|---|---|---|
| clover | White clover | Trifolium repens | E | Open grassland; rhizobial nitrogen fixation |
| nettle | Common nettle | Urtica dioica | E | Nutrient-rich damp edges; larval host, not nectar |
| heather | Heather | Calluna vulgaris | E | Acid heath; late-season flowers |
| bluebell | English bluebell | Hyacinthoides non-scripta | E | Spring woodland floor |
| yarrow | Yarrow | Achillea millefolium | B | Meadow; summer/autumn flowers |
| foxglove | Common foxglove | Digitalis purpurea | B | Acid clearings; no game food |
| meadowsweet | Meadowsweet | Filipendula ulmaria | B | Wet meadow; pollen resource |
| wild_garlic | Wild garlic | Allium ursinum | B | Spring moist woodland; no game food |
| cowslip | Cowslip | Primula veris | B | Base-rich open grassland |
| wood_anemone | Wood anemone | Anemone nemorosa | B | Spring woodland floor; no game food |
ferns_mosses (10; five ferns P/T, five mosses M)
| id | Common name | Scientific name | Owner | Habitat emphasis |
|---|---|---|---|---|
| bracken | Bracken | Pteridium aquilinum | B | Acid slopes/clearings; competition descriptor |
| lady_fern | Lady-fern | Athyrium filix-femina | B | Damp shaded woods |
| male_fern | Male-fern | Dryopteris filix-mas | B | Shaded woods |
| harts_tongue | Hart's-tongue fern | Asplenium scolopendrium | B | Damp base-rich shade |
| polypody | Common polypody | Polypodium vulgare | B | Acid rock/bark/woodland |
| sphagnum | Blunt-leaved bog-moss | Sphagnum palustre | B | Saturated acid bog/wet woodland |
| haircap_moss | Common haircap | Polytrichum commune | B | Damp acid soils |
| moss | Cypress-leaved plait-moss | Hypnum cupressiforme | E | Shady soil, wood, bark and rock |
| fork_moss | Broom fork-moss | Dicranum scoparium | B | Acid woodland/heath |
| star_moss | Swan's-neck thyme-moss | Mnium hornum | B | Damp woodland banks |
fungi (10; F)
| id | Common name | Scientific name | Owner | Habitat emphasis |
|---|---|---|---|---|
| fly_agaric | Fly agaric | Amanita muscaria | B | Ectomycorrhizal: birch/pine/spruce |
| birch_bolete | Brown birch bolete | Leccinum scabrum | B | Ectomycorrhizal: birch only in this model |
| bay_bolete | Bay bolete | Imleria badia | B | Ectomycorrhizal: conifers/beech/oak |
| chanterelle | Chanterelle | Cantharellus cibarius | B | Ectomycorrhizal woodland roots |
| wood_blewit | Wood blewit | Collybia nuda | B | Litter saprotroph; autumn/winter |
| shaggy_inkcap | Shaggy inkcap | Coprinus comatus | B | Grassland-soil saprotroph |
| turkey_tail | Turkey tail | Trametes versicolor | B | Broadleaf deadwood saprotroph |
| oyster_fungus | Oyster mushroom | Pleurotus ostreatus | B | Broadleaf deadwood; late-season fruiting |
| honey_fungus | Honey fungus | Armillaria mellea | B | Deadwood here; parasitism descriptive only |
| birch_polypore | Birch polypore | Fomitopsis betulina | B | Birch deadwood here; parasitism descriptive only |
aquatic (10; P/W)
| id | Common name | Scientific name | Owner | Placement niche |
|---|---|---|---|---|
| duckweed | Common duckweed | Lemna minor | B | Surface; 1–6 depth units |
| yellow_waterlily | Yellow water-lily | Nuphar lutea | B | Surface; 1–3, mud anchor |
| white_waterlily | White water-lily | Nymphaea alba | B | Surface; 1–3, mud anchor |
| water_crowfoot | Common water-crowfoot | Ranunculus aquatilis | B | Surface abstraction; 1–3, mud anchor |
| water_mint | Water mint | Mentha aquatica | B | Wet bank, dry destination |
| water_forgetmenot | Water forget-me-not | Myosotis scorpioides | B | Wet bank, dry destination |
| brooklime | Brooklime | Veronica beccabunga | B | Wet bank, dry destination |
| water_starwort | Common water-starwort | Callitriche stagnalis | B | Submerged abstraction; 1–4, mud anchor |
| hornwort | Rigid hornwort | Ceratophyllum demersum | B | Submerged/rootless; 1–4, water substrate |
| pondweed | Broad-leaved pondweed | Potamogeton natans | B | Surface; 1–3, mud anchor |
lichens (10; L)
| id | Common name | Scientific name | Owner | Habitat emphasis |
|---|---|---|---|---|
| reindeer_lichen | Reindeer lichen | Cladonia rangiferina | B | Open acid heath; wildlife browse |
| oakmoss | Oakmoss | Evernia prunastri | B | Bark in light woodland |
| old_mans_beard | Old man's beard | Usnea subfloridana | B | Humid bark/branches |
| lichen | Map lichen | Rhizocarpon geographicum | E | Acid siliceous rock, not generic soil |
| dog_lichen | Dog lichen | Peltigera canina | B | Mossy soil; cyanobacterial fixation |
| lungwort_lichen | Lungwort lichen | Lobaria pulmonaria | B | Humid woodland bark; cyanobacterial cephalodia |
| sunburst_lichen | Common orange lichen | Xanthoria parietina | B | Well-lit nutrient-enriched bark/base-rich stone |
| hammered_shield | Hammered shield lichen | Parmelia sulcata | B | Woodland bark |
| cup_lichen | Mealy pixie-cup | Cladonia chlorophaea | B | Acid soil/humus, distinct species below |
| pixie_cup | Pebbled pixie-cup | Cladonia pyxidata | B | Soil/humus; not a duplicate of chlorophaea |
Exact public interface
Loading the file returns factory(hearth, api) -> B. The factory has no registration side effects and publishes no globals. Main assigns hearth.botany before loading succession. Botany installs no scheduler, globalstep, ABM, LBM, mapgen callback, timer or liquid transformation. mods/hearth/succession.lua consumes this policy in its existing eight-probe loop.
Catalogue/query APIs
B.groups,B.group_order: ordered arraystrees, shrubs, grasses, herbs, ferns_mosses, fungi, aquatic, lichens.B.catalogue: ordered 80-record snapshot, group order then manifest row order.B.get(value) -> record|nil;B.list(group_or_nil) -> ordered records;B.group_of(value) -> group|nil;B.kind(value) -> id|nil.valuemay be a bare ID, fullhearth:node name or{name=...}. Trees also resolve canonical_seedling,_young,_mature,_leaves,_log,_planks. Seasonal names resolve throughhearth.seasons.kindwhen available. Generic patches and foreign namespaces do not resolve.- Every returned record is a detached copy. Editing a snapshot cannot change internal policy.
- Record fields:
id,common,latin,group,node,texture,existing,food,toxic,seasons(boolean set),tags(boolean set),niche; flowering taxa also haveflowering, the three game-fruit taxa havefruiting(both boolean sets). nichefields:substratesset, inclusivelight={min,max}on 0–15,moisture={min,max}on 0–1,ph={min,max}in pH units,water={min,max}in game node-depth units,aquaticstring. Some also requirehostsset ornutrientsminimum.
Read-only habitat selection
B.suitable(value, h, season) -> boolean and B.choose(p, h, season) -> bare_node_kind, record | nil use only supplied observations. p must contain finite integer x,y,z within ±30990; h must have loaded=true and finite light, moisture, ph. Missing/invalid facts do not receive optimistic defaults. season is exactly Spring, Summer, Autumn or Winter.
h.ground is a canonical bare/full support node or node table. h.substrate, when supplied, overrides the direct substrate for land/bark/deadwood niches. Bark and deadwood are semantic observations, not assertions that arbitrary planks/logs are safe recruitment sites. The ecological owner must derive those observations from unmodified natural substrate and enforce owner/protection checks. Do not treat crafted timber or planted trees as free fungal substrate.
h.host is a nearby identified tree ID/stage/root association, mandatory for host-specific fungi. Its search radius and finite sampling budget belong to the existing ecological scheduler. Presence of an unrelated tree does not satisfy a birch specialist. h.nutrients must be at least one for nettle. pH is a game support-class observation; callers lacking it should explicitly derive a documented approximation from the substrate, not silently infer that all plants fit.
h.aquatic is land, bank, surface or submerged; land may omit it. h.water is numeric column depth, not a boolean or permission to replace a water node; land/bank may omit it (zero). The selection represents a candidate only:
| Mode | Required observations | Safe external placement rule |
|---|---|---|
| land | Depth zero; accepted substrate | Loaded air destination above accepted natural substrate |
| bank | Explicit bank, depth zero, wet support |
Loaded air destination beside real freshwater, never inside/over it |
| surface | Explicit surface, freshwater=true, allowed positive column depth; accepted mud bottom |
Flat pad in a distinct air cell above the actual surface; source node below stays unchanged |
| submerged | Explicit submerged, freshwater=true, positive column depth; rooted starwort needs mud bottom, rootless hornwort needs substrate=water |
Succession places a qualitative shallow-water stand sprite in the separate air cell above conserved source water. It is not literally rendered inside the liquid. No source replacement, fake liquid, water clearing/refilling or flood-producing liquid flora |
Surface depth ranges/anchors are intentionally coarse: even floating duckweed uses a valid freshwater bottom observation rather than an unbounded “water somewhere” fallback. Succession checks up to six consecutive loaded hearth:water_source cells and an accepted bottom, with authority/markers checked on every cell. Flowing water, unknown bottoms, over-depth or unloaded columns fail closed. Surface/submerged mode for a new stand is position-deterministic; established stands retain their species mode. Thus all ten aquatic taxa have establishment/spread/age pathways, but hornwort/starwort use above-water stand markers, not scientifically exact submerged geometry. register_nodes keeps direct source-water item placement disabled. Bank flora occupies dry cells beside actual water.
choose considers all 80 records in a deterministic position-hashed order, skipping trees unless h.include_trees=true. It returns an unprefixed actual node kind, e.g. bluebell, water_mint or beech_seedling, plus a detached descriptor. It never writes the map, chooses an occupied cell, checks claim ownership itself, consumes nutrients or rescans the world. The caller must independently verify loaded, empty, unmodified destination/support and authorization immediately before any write, using its existing bounded scheduler. No plant replaces another, spreads water or creates nutrients here.
Interactions and finite effects
B.has_tag(value, tag) -> boolean.B.interactions(value) -> tag-keyed descriptor copieswith adescription, and where applicablecaporenabled=false.B.active(value, season) -> boolean: establishment/visible-season gate, not an instruction to destroy winter-dormant perennial plants. Four spring woodland herbs gate to Spring; evergreen trees, mosses/lichens and persistent bracket fungi have broader windows.B.pollinator(value, season) -> boolean: actual flowering tag and flowering season. Oak, wind-pollinated grasses, nettle, mosses and fungi do not become nectar sources. Meadowsweet and dog rose represent pollen as well as nectar relations.B.edible(value, season) -> boolean: game berry permission only, independent of wildlife browse; only bilberry/raspberry in Summer and blackberry in Summer/Autumn return true.B.browse(value, season) -> boolean: active wildlife relationship; not a universal diet rule. Wildlife owner must still choose an appropriate animal diet.B.resin(value) -> boolean: only the catalogue's pine/spruce/juniper resin tag. It grants no item or extraction callback.B.nitrogen(value, current) -> suggested_delta: only nitrogen-fixer-tagged taxa;min(1,max(0,2-current)), zero for invalid/negative current. Alder/Frankia, clover/rhizobia and cyanobacterial lichen partners are distinct biological associations. Ecology owner must apply a per-site contribution/cooldown and metadata cap of two; repeatedly calling this pure query is not permission for unlimited fertilizer.B.root_fungi(value, tree, budget) -> transfer_ceiling: only ectomycorrhizal fungi matching the supplied host, at most one and at most the finite positive existing budget. A nearby host can receive a bounded establishment advantage through that owner's already-budgeted resource transfer. Caller debits the same budget; the function creates nothing and never independently raises soil nitrogen. Tree ectomycorrhizal tags alone are not free fungal boosts. Saprotrophs receive no root-fungus boost.
saprotroph describes recycling existing litter/wood: any later benefit must consume existing substrate, not mint nutrients. engineer describes physical substrate/water retention or aquatic cover; it does not grant terraforming. nursery means conditional cover/microhabitat. parasite and allelopathy are disabled descriptive interactions: honey fungus/birch polypore do not infect player trees and bracken never kills neighboring plants. The module mutates no ecological state.
Registration and harvest
B.register_nodes(register_node) accepts the content registrar taking bare names. It is idempotent and skips known existing IDs, all ten trees and any already present api.registered_nodes[full_name]. In an otherwise empty registry it registers 62 nodes (70 non-tree taxa minus eight existing understory IDs). It registers no recipes, aliases, items or tree stages/resources. Existing flora definitions are never overridden. Main should load this factory after seasons and call registration after legacy diversity registration.
New terrestrial plants/fungi/shrubs are conventional crossed plantlike sprites with no meshes/sculptures. Surface aquatics are thin nodeboxes wholly inside ±0.5 of the node. They are not water; submerged sprites are not given liquid behavior or water groups. All are non-walkable and buildable_to=false. Ordinary herbs, mosses, fungi and lichens dig to their own node item. All new shrubs dig to hearth:sticks, so digging/replanting cannot erase a berry cooldown and mint a fresh fruit-bearing bush. Placement marks player_placed=1; normal construction/protection handling is supplied by the existing registrar. There is no new growth timer.
B.harvest(pos, player) -> success_boolean, count_or_reason is the only resource mutation API. Berry callbacks return the original wielded stack. It:
- Validates finite integer bounded coordinates and a real player; looks up current
hearth.construction.allowed(pos, player, "use")at callback time. Missing policy denies access; no permissive fallback. Existing policy owns reach, claim and protection checks. - Re-reads the loaded node and requires its exact canonical three-bush ID, then current
hearth.climate_at().seasonand game fruiting season. - Checks persisted string metadata
botany_ready_at, rejecting malformed/negative/nonfinite values. Missing metadata means initial fruit stock; future timestamps deny until ready. - Requires inventory room for
hearth:berries 2; full inventory neither changes stock nor starts cooldown. - Locks the bush by writing a finite timestamp one real day ahead before inserting at most two berries. This blocks callback reentrancy. A completely rejected insertion restores the old timestamp; partial delivery consumes that cycle, never exceeds two or drops overflow into the world. Unexpected insertion results/errors leave the lock in place rather than duplicate stock.
The factory may precede construction publication, but harvest cannot. Time uses optional injected api.now() (numeric Unix seconds, for tests), otherwise os.time(). No offline catch-up or accumulating fruit: one ready bush gives at most two per cooldown even after months away, and cooldown metadata survives module reload. New callbacks are installed only on bilberry, blackberry, raspberry; generic existing berry-bush behavior is untouched.
Reasons: invalid, denied, species, season, clock, metadata, cooldown, inventory; success returns delivered count 1 or 2. No player health changes, medicinal effects, wild-consumption guidance or automatic fertilizer is added.
Ecology80 integration and bounds
The single succession loop owns recruitment, local spread, dormancy, senescence and decomposition for all 80 catalogue entries. It uses the actual node kind returned by B.choose, including species seedling suffixes, and rechecks B.suitable against destination facts before writes. Trees enter older gaps only after 7,200 active seconds; other recruits establish after 180 active seconds (90 with existing nutrients). No second scheduler, unbounded radius, map emergence or offline replay is introduced. Existing eight column probes/second, radius 12, twelve sampled heights, 8,192-entry age cache, 60-second durable attempt cooldown and 1,200-second maximum continuity gap remain.
S.habitat(pos) is read-only. Its 5×5×5 stencil now exposes exact catalogue dimensions: finite light, moisture, ph, nutrients, depth-valued water, separate near_water, ground, semantic substrate, freshwater, aquatic, host, active browse count (edible, retained for wildlife compatibility), seasonal pollination, nursery and host-fungus IDs. pH is an explicit game support-class approximation: peat 4.5; podzol/granite 5; alpine turf/slate/sandstone/scree/stone/forest floor/bark/deadwood/litter 5.5; grass/soil/alluvium/sand/basalt 6.5; limestone 7.5. Missing support observations fail closed. Nursery-tagged natural cover slows accumulated habitat stress by 25%; it creates neither water nor nutrients. Fungal host observations use only nearby identified natural trees or recorded natural wood species, never player timber.
Non-tree active lifetimes (seconds): shrubs/lichens 86,400; grasses/aquatic 21,600; herbs 14,400; ferns/mosses 43,200; fungal fruit bodies 2,400. Dormant perennials occupy their cells and pause, not disappear at first frost. Soil-supported vegetation becomes litter; rock/bark/wood/litter/water stands disappear without replacing their support. Fungal fruit bodies do not independently mint nutrients through litter. Saprotrophs advance only an existing, natural, authorized litter/deadwood clock by at most 60 seconds per attempt. The substrate's eventual consumed decomposition pays once using the existing capped nutrient path.
All nitrogen-fixer tags use a persisted two-unit soil support budget (succ_fixed_nitrogen), shared across death/recolonization/restart; a bark-dwelling fixer without a soil support gets no fertilizer effect. Matching ectomycorrhizal fungi reduce seedling establishment age from 21,600 to 16,200 only with a positive existing soil resource budget; successful growth debits at most one from that same budget. Failed growth creates/debits nothing. parasite and allelopathy remain deliberately disabled descriptors; no tree infection or neighboring-plant damage. engineer/resin stay habitat/resource descriptors, not autonomous terraforming/item generation. Pollination is exposed for wildlife/harvest integration, not a berry-yield multiplier: the unchanged botany harvest policy still returns at most two berries per real-day cooldown. Succession preserves a valid botany_ready_at; other non-succession provenance metadata still opts plants out.
Owned full-block tree lifecycle
D.tree_plan(species, stage) supplies fresh full-block plans for all ten species. Succession validates integer offsets within ±4 horizontally and 0–9 vertically, at most 810 entries, no duplicate/foreign names, and a root. One global tree-plan reservation per wall-clock second, including denied attempts, covers plan construction/preflight/application regardless of player count. Old/new plan union work is bounded (at most two plans); there are no dynamic per-frame world tree registries.
Every destination and its immediate support must be loaded, unclaimed, externally unprotected and unmarked. New components require air; growth never silently replaces even natural groundcover. Existing components must match the root-key succ_component, species/stage expected node (season-canonicalized) and rotation. succ_tree_stage and succ_species persist on the root; components carry its plain coordinate key. Components never independently age or pay nutrients. A tree's own owned leaves do not shade its own root into automatic starvation; neighbouring crowns still shade recruits. Pine and spruce retain winter shade.
Senescence atomically clears only the root's matching components and leaves one ground-supported full-cube fallen log, param2=12; existing content supplies the axe requirement and one-log drop. No floating standing log pile, sculpted tree, or chain of extra resource logs is created. Any protected/marked/foreign component blocks collapse rather than being destroyed. Natural epiphytes losing their owned substrate are removed in the same bounded preflight, while foreign attachments block it.
S.tree_removed(pos, oldnode) -> boolean is the optional after-dig handoff. A standard register_on_dignode hook calls it when available. It validates an empty loaded root, old stage identity and every remaining matching owned component; it cannot clear unrelated mapgen/player wood. External removals that do not invoke this hook must explicitly call the handoff; a denied/unloaded cleanup is not queued/replayed. Unmanaged pre-existing mapgen tree canopies are not retroactively adopted as managed trees. The independently registered generic deadwood adoption remains intact.
Focused validation and integration boundary
tests/botany_spec.lua is a standalone Lua 5.1+ mocked-API suite. It checks all 80 positive niche vectors and each light/moisture/pH/substrate rejection; 8×10 disjoint counts; unique scientific names; exact legacy mappings; seasonal/host/water distinctions; texture and registration ownership; bounded interactions; toxic/food exclusion; denied/full/partial/reentrant harvest; reload/cooldown and invalid clocks/metadata.
Standalone focused suites: tests/botany_spec.lua, tests/succession_spec.lua and tests/seasons_spec.lua. They include all 80 real selector outputs and recruitment/spread/lifecycle pathways with supplied species niche vectors, separately tested actual water/wood/pH habitat sampling, water preservation/authority, atomic real tree plans, owned cleanup/restart, malformed plans, concurrency bounds, finite fungal/nitrogen effects and cube-safe seasonal registration. Verified markers: BOTANY_SPEC_PASS 32, LAST_HEARTH_SUCCESSION_PASS 63, LAST_HEARTH_SEASONS_PASS 12 (107 named cases; the all-80 case additionally loops every taxon). Controlled niche-vector coverage is not evidence that all species spawn in one real-world patch. Require each final marker, all named passes and empty stderr; Fengari exit zero alone can hide assertion failures. On the network workspace, module source was read from disk once and executed in-memory to avoid repeated SMB reads timing out; tests/production modules were not rewritten for staging. No full engine or persistent world is run for this integration. Visual correctness, real-engine harvest/dig callback wiring and empirical gameplay/performance acceptance remain to be verified by main.
Security review followed CodeGuard: centralized runtime authorization, deny-by-default missing policy, finite validated positions/time, persistent bounded harvest, inventory preflight and reentrancy lock. No credentials, certificates, cryptography, network operations or dynamic executable inputs are introduced.