Files
2026-11-05 09:57:11 -05:00

36 KiB
Executable File
Raw Permalink Blame History

Botany: 100 temperate taxa and calendar integration

Scope and evidence

The catalogue in mods/hearth/botany.lua has 100 distinct real taxa in eight disjoint groups: 13 trees, 14 shrubs, 10 grasses, 22 herbs, 11 ferns/mosses, 10 fungi, 10 aquatic taxa and 10 lichens. It represents a north-west/central European temperate landscape mosaic, not one plant community or a claim that every species is native everywhere. Hazel is counted among trees, heather among herbs, and lichens separately from other fungi. Existing generic gathering patches are not part of this count.

Taxonomic/reference authorities for maintaining these names and broad habitats:

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; diversity/resources own tree stages and materials. Generic berry_bush, fern, wildflowers and meadow_grass remain outside the 100.

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 100: hearth_botany_<id>.png. Botany registers 79 non-tree nodes (87 non-trees minus eight legacy understory IDs). Diversity/terrain own all thirteen tree stages, bark/end-grain cubes, leaves and planks. No random tint or seasonal mesh substitutes for species materials. Seasonal copying preserves bark faces, facedir, callbacks and drops. Assets and native-engine visual validation remain the art/main integration owners' responsibility.

Exact twenty additions (counts above include these)

ID Latin identity from lifecycle contract Group / ecological emphasis
dandelion Taraxacum officinale herbs; open meadow, spring–autumn flowers
daisy Bellis perennis herbs; short open grassland flowers
red_clover Trifolium pratense herbs; summer/autumn flowers, bounded nitrogen fixation
birdsfoot_trefoil Lotus corniculatus herbs; drier meadow, flowers, bounded nitrogen fixation
ribwort_plantain Plantago lanceolata herbs; meadow browse, wind-pollinated, no nectar aura
selfheal Prunella vulgaris herbs; meadow summer/autumn flowers
knapweed Centaurea nigra herbs; meadow late flowers and cover
oxeye_daisy Leucanthemum vulgare herbs; summer meadow flowers
field_scabious Knautia arvensis herbs; drier base-rich meadow flowers
teasel Dipsacus fullonum herbs; summer flowers and seedhead cover; biennial fallback
cow_parsley Anthriscus sylvestris herbs; hedge margins, spring/summer flowers
garlic_mustard Alliaria petiolata herbs; shaded edges, second-season spring flowering policy
honeysuckle Lonicera periclymenum shrubs; hedge/woodland edge flowers; no food
ivy Hedera helix shrubs; evergreen cover, autumn flowers, spring seed window; no food
gorse Ulex europaeus shrubs; open acid scrub, flowers including winter, bounded nitrogen fixation
broom Cytisus scoparius shrubs; open acid scrub, spring/summer flowers, bounded nitrogen fixation
crab_apple Malus sylvestris trees; spring flowers, broad round crown
wild_cherry Prunus avium trees; spring flowers, taller horizontal branch tiers
field_maple Acer campestre trees; spring flowers, broad lobed crown
holly_fern Polystichum setiferum ferns_mosses; evergreen damp shade, commonly soft shield-fern

The historical 80-entry manifest below lists the retained baseline; append these twenty, not twenty per group. No addition grants human food or a new berry output. Nitrogen-fixing Lotus corniculatus is birdsfoot trefoil, not an aquatic lotus. Climbing ivy/honeysuckle use stand sprites rather than simulated climbing geometry.

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 arrays trees, shrubs, grasses, herbs, ferns_mosses, fungi, aquatic, lichens.
  • B.catalogue: ordered 100-record snapshot, group order then retained and added 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.
  • value may be a bare ID, full hearth: node name or {name=...}. Trees also resolve canonical _seedling, _young, _mature, _leaves, _log, _planks. Seasonal names resolve through hearth.seasons.kind when 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 have flowering, the three game-fruit taxa have fruiting (both boolean sets).
  • niche fields: substrates set, inclusive light={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, aquatic string. Some also require hosts set or nutrients minimum.

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 100 records in a deterministic position-hashed order, skipping trees unless h.include_trees=true. It returns the actual bare node kind plus a detached descriptor. The caller independently verifies loaded empty unmodified destination/support and authorization immediately before any write. No plant replaces another, spreads water or creates nutrients through this query.

Interactions and finite effects

  • B.has_tag(value, tag) -> boolean.
  • B.interactions(value) -> tag-keyed descriptor copies with a description, and where applicable cap or enabled=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.seeding(value, season) -> boolean: qualitative seed-season window; succession additionally requires calendar maturity. This is not a physiological reproduction authorization or a replay queue.
  • 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 existing IDs, all thirteen trees and already registered definitions. It registers 79 nodes in an empty registry, no recipes/aliases/items/tree resources. Main loads the factory after lifecycle/seasons and calls 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:

  1. 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.
  2. Re-reads the loaded node and requires its exact canonical three-bush ID, then current hearth.climate_at().season and game fruiting season.
  3. Checks persisted string metadata botany_ready_at, rejecting malformed/negative/nonfinite values. Missing metadata means initial fruit stock; future timestamps deny until ready.
  4. Requires inventory room for hearth:berries 2; full inventory neither changes stock nor starts cooldown.
  5. 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.

Calendar integration and bounds (version 1)

Main must assign the pure namespace hearth.lifecycle before botany/content. This change does not edit bootstrap files owned by main. See the exact lifecycle API and evidence. Succession consumes plant(id) and phase(profile, 0, age_seconds) with conservative upper-endpoint thresholds, retaining field-level evidence/fallback labels. Its root anchors, not the loaded activity cache, determine age. One real day is 86,400 seconds; one mean year is 365.2425 days. No ten-minute years, accelerated stage counters or nutrient age multipliers remain for catalogue plants/trees.

The existing scheduler still performs eight column probes/second, radius 12, twelve sampled heights, at most 96 seasonal swaps and one globally reserved full tree-plan operation per wall-clock second. The 8,192-entry continuity cache and 1,200-second gap still bound loaded work, stress and material decomposition; they no longer truncate biological age. Empty-gap colonization remains a coarse 90/180-active-second recruitment opportunity (woody gaps after 7,200), not a claim that a real seed germinates in minutes. New recruits start calendar age zero and must wait their full profile thresholds before young/mature transitions and propagation. Reconciliation never emerges terrain, scans the whole world or replays missed seasons.

Root persistence and migration

  • succ_birth_at: validated UTC epoch anchor; for a natural recruit this is actual recruitment time. succ_lifecycle_version=1 and succ_lifecycle_policy=calendar_v1_conservative_max label this format and threshold policy.
  • succ_initial_age_seconds: separately recorded inferred establishment age, zero for natural_seed. It avoids inventing negative/pre-epoch birthdays for ancient-looking generated vegetation. Biological age is initial age plus the entire difference between current epoch and birth anchor.
  • succ_lifecycle_origin: natural_seed, legacy_established or worldgen_established. Legacy succ_age is retained unchanged, never multiplied or subtracted into a birthday. Migration anchors once at NOW; stage inference is a documented assumption, not historical observation. Seedlings infer their profile emergence threshold, young roots the juvenile threshold, mature roots and un-staged botanical stands their known maturity threshold. Unknown maturity infers zero, not a fabricated age.
  • succ_lifecycle_profile, succ_lifecycle_seed: exact identity and persistent deterministic position seed. Version 1 intentionally uses profile maxima, not sampled thresholds; the stored seed reserves reproducibility without claiming a measured age distribution.
  • succ_last_observed_at: durable high-water timestamp. Clock rollback pauses reconciliation until the clock catches up; it never resets birth or subtracts age. Malformed timestamps, seeds, profile identity or unknown versions fail closed without migration/reroll. Stage swaps preserve all root anchors. Components reference the root and do not age separately.
  • succ_seed_epoch: next allowed present-time seeding opportunity, advanced before one attempt (trees one mean year, understory 30 days). Missed opportunities are not queued. Current seed season, maturity, habitat, loaded air and protection still apply. Unknown maturity does not authorize propagation. succ_litter_epoch similarly bounds mature litter attempts to 30 days.

Known unmodified botanical stands and soil-supported worldgen log roots adopt worldgen_established; they are not converted to seed sprites, assigned fake historical birthdays, expanded or killed on load. Existing mapgen canopies remain unmanaged timber. Species/generic log roots retain their node and mature-stage provenance. Every adoption checks source/support ownership, protection and markers. Load callbacks only mark/invalidate continuity; first bounded root observations initialize calendar anchors.

Winter/cold pauses visible growth transitions, seeding and loaded stress, not calendar age. On a later favorable visit an overdue plant may advance one stage; no historical season integration is claimed. Biennial root/rosette policy persists across winter, not instant flowering or death. All lifespan endpoints are informational; there is no automatic age-based plant death, including unknown-lived fungi/lichens. Historical growing seasons, seed banks, annual stem death and fungal fruitbody turnover need future species-specific models. Unfavorable habitat records stress but does not kill a calendar-managed organism using the former ten-minute threshold.

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.

Material decomposition (generic dung/litter/deadwood/fungi) retains bounded loaded accounting; these are resource-cycle approximations, not living-organism years. Botanical fungi do not independently mint litter nutrients. Saprotrophs advance only an existing natural authorized substrate clock by at most 60 seconds per attempt; consumed material pays once through the capped nutrient path.

All nitrogen-fixer tags use a persisted two-unit soil support budget (succ_fixed_nitrogen) shared across restart/recolonization; additions require at least 90 calendar days and stop at local fertility four. New gorse, broom, red clover and birdsfoot trefoil use the same cap. Root fungi may transfer/debit at most one existing soil unit when an independently age-eligible seedling grows; they never reduce calendar thresholds. Failed growth debits nothing. Parasite/allelopathy remain disabled descriptors. Pollination is habitat, not a berry multiplier; harvest remains at most two berries per real-day cooldown.

Owned full-block tree lifecycle

D.tree_plan(species, stage) supplies fresh full-block plans for all thirteen 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.

Automatic senescence/collapse from age is disabled. The owned-component cleanup mechanism remains for explicit root removal; it cannot clear unowned mapgen/player timber. Any protected/marked/foreign component blocks cleanup. Natural epiphytes losing an owned substrate participate in the same bounded preflight; 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 checks all 100 positive niche vectors and dimension rejections, exact uneven group counts, lifecycle Latin identities, legacy mappings, seasonal/host/water distinctions, registration ownership, finite interactions and denied/full/partial/reentrant harvest. Calendar-managed seedlings/juveniles do not supply mature flower habitat: biennial second-season policy needs both maturity and the current flower season.

Focused suites cover all 100 real selector outputs with controlled niche vectors, actual water/wood/pH sampling, calendar migration and rollback, no guessed mortality, bounded material effects, atomic block plans and cube-safe seasons. Require all named successes, final suite markers and empty stderr; Fengari exit zero alone can hide failures. Source is read from disk once into an in-memory loader to avoid SMB repeated-read overhead. Native-engine/asset/bootstrap integration and empirical gameplay remain main-owner verification work; controlled habitat vectors are not real-world distribution evidence.

Calendar expansion validation: 178 named passes, empty stderr, all six final markers: botany 38, diversity 15, biomes 26, seasons 16, ecology 9, succession 74. Only the requested owned files were edited. The separately owned lifecycle suite and schema/content/art/bootstrap integration are not included in this result.

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.