Coheronia Wiki

Coheronia - Variable Matrix

HTML wiki page generated from the current repo-backed markdown source. This keeps browsing in HTML while preserving markdown as the maintainable source format.

Generated HTML Page

Coheronia - Variable Matrix

State: audited 2026-07-16 against the native HUD-kit stabilization, authored opening-cel integration, and 120-file body-specific player-gear program.

Authority Surfaces

SurfaceAuthorityConsumed by
Blocksdata/blocks.jsonBlockRegistry, world, player, settlement_model, hud
Recipesdata/recipes.jsonplayer, town_hall
Craft stations (FQ-11)data/recipes.json stations (workbench/furnace/anvil: prereq + build_cost) + station recipes (station, output_to, equip_slots)BlockRegistry.station_defs/station_def/recipes_for_station; town_hall.build_station (spends stockpile, prereq-gated, stations_built saved in to_dict) and town_hall.craft_station (inputs from stockpile; smelted ingots output_to stockpile, anvil gear equips with empty-slot+fit guard before consuming); hud rebuilds the town-panel station section from data each refresh; metal gear is gated ore -> furnace ingot -> anvil (validator-enforced: no anvil recipe consumes raw ore)
Farming (FQ-12)farm_soil/crop_seedling/crop_ripe blocks in data/blocks.json (crops requires_support, non-solid, non-placeable; crop_ripe drops food + a seed) + craft_seeds recipe (data/recipes.json, food -> seeds)player.try_farm (one key farm_action/G: tills dirt/grass via world.till_soil, plants a seed on farm_soil via world.plant_crop, consuming one crop_seeds); world._tick_crop_growth ripens seedling -> ripe after CROP_GROW_SECONDS on tilled soil, removes unsupported crops (never floats, never regrows into invalid cells), timers in crop_growth persist via serialize_crop_growth/parse_crop_growth in save_manager; world.farm_tile_count() -> game_root.summary() food-yard score
Map / scouting (FQ-15)discovered bands in scripts/world/map_state.gd (coarse REGION=16 grid; no JSON authority); the scouting hook is the explorer biome_reveal perk map_discovery_speed in data/progression/perks.jsongame_root._process reveals bands around the player (_scout_reveal_radius reads the perk); map_snapshot builds hall/player/ore/threat markers over revealed bands only; hud/scripts/ui/map_panel.gd draw it (M toggles); map_revealed_serialized/apply_map_revealed persist the compact band list via save_manager (map_revealed)
Goal panel (FQ-14)objective list in scripts/main/goal_tracker.gd GOALS (id/text/hint) — no JSON authoritygame_root._goal_snapshot derives per-objective booleans from live state (inventory wood/stone, cached light_score, town_hall.total_stock, tool_tier/axe_tier/stations_built, day_count); goal_tracker.note prefix-latches and current() feeds hud.update_goal; toggle_goals (O) hides the panel. Goal progress remains presentation-only and is re-derived on load; panel visibility is a profile-level HUD preference.
Settlement formulasdata/settlement_rules.jsonsettlement_model.gd via Godot Expression
World settingsdata/world_settings.jsonWorldConfig, shell UI, world generation, gameplay systems
Character datadata/character_data.jsonshell UI, player.apply_character, role item grant
Player cosmetic variant (FQ-13P3 + art run)character record visual_variant int (shell.json; game_state.create_character, default_visual_variant legacy default; NOT in world saves)player.visual_variant -> player_visual._select_body_texture picks art/generated/players/<body_id>_NN.png (0 = canonical, k>0 = pool[k-1] wrapped, else canonical); all ten body ids have _01/_02; shell_ui._refresh_look_range exposes only the real pool length
Equipment (FQ-03)data/equipment.jsonBlockRegistry equipment helpers -> player gear API, hud panel, game_root carried-state load, save_manager
Legacy UI hooks (FQ-13P2/FQ-19)art/generated/ui/<id>.png (15 reserved ids generated by scripts/gen_ui_placeholders.py; convention-picked, no manifest entry)Older slot/orb/button consumers and code-drawn fallbacks; retained as resilience paths when the primary HUD kit is incomplete
Primary HUD dock kit (2026-07-16 stabilization, contract v2)19 native-size RGBA assets plus hud_dock_layout.json in art/source_templates/hud_dock/, promoted one-for-one to art/generated/ui_painted/ by scripts/art/sync_hud_kit.pyhud._load_hud_kit_layout/_hud_kit_available select the native kit first; JSON supplies every dock/vessel/fill/label/slot/button rectangle plus inner icon/count/hotkey/visible-label rectangles, alpha rules, state families, trim keep-outs, and manifest-driven non-interactive decorative layers. Runtime children own health, attunement, icons, counts, hotkeys, selection, labels, actions, and FX. New interactive controls still require a registered action. The FQ-21 sliced band and FQ-19 modular dock remain fallbacks.
Movable HUD modulesprofile hud_layout schema v5 (crest, goal, events, map, modules; dock is transform-invariant)hud.gd move/resize/edit controls; Map and Events use independent non-overlapping defaults and may remain visible together; older geometry schemas reset to current defaults
Visual assets (FQ-07 + 2026-07-14 art run)data/visual_assets.json + art/generated/<category>/<id>.png convention; scripts/asset_audit.py derives rendered block/item ids plus every live enemy and live enemy dropBlockRegistry.visual_texture -> world._make_block_texture (blocks), simple_threat._draw (enemies), hud toolbelt/grids (items via item_icon); all current rendered block/item/live-enemy ids have canonical PNGs, while missing future images still fall back; loaded via Image.load_from_file; explicit json entries validator-fail when broken, convention gaps are INFO-only
Variant pools (FQ-09V + art run)<id>_01.png … convention (consecutive, max 8) or explicit arrays in data/visual_assets.json; current pools: 17 blocks × 3, 6 enemies × 3, 10 player bodies × 2BlockRegistry.visual_variant_textures -> blocks via deterministic seed+cell choice, enemies via lifetime-stable spawn hash, players via character-owned Look index; empty pool = canonical/fallback path; asset_audit.py --strict fails gaps, more than eight files, unreadable PNGs, and wrong dimensions
Pixel-art normalizationreviewed image-model source staged outside the repo; scripts/art/prepare_pixel_asset.py crops/scales, palette-reduces, hardens alpha, and seam-locks opaque tiles after the installed imagegen chroma helper handles cutoutsexact target PNGs under art/generated/; contact-sheet review plus strict audit/validator/runtime smoke gate promotion; source generations remain outside the public repo
Item metadata (FQ-09)data/items.jsonBlockRegistry.display_name fallback chain (blocks -> items.json -> id), item_description (tooltips), item_fallback_color -> item_icon swatches for the FQ-09 icon grids; unknown ids get a stable hash-derived hue
Ore families (FQ-10)ore-family blocks in data/blocks.json (coal/copper_ore/tin_ore/iron_ore/silver_ore/crystal — each drops itself, pick-preferred, tier 1 or 2) + data/world_settings.json ore_table (per-family min/max depth, frequency, threshold, unique seed_offset; validator-enforced)WorldGen._build_ore_families/_ore_family_at place families by depth band on independent noise channels, claiming only cells that would be stone (the generic ore vein is untouched); ore_abundance scales all thresholds and 0 disables every ore; deterministic per seed+cell, never saved; every family now has canonical block/item art and three block variants, with fallback colors retained for resilience
Enemiesdata/enemies.json (FQ-13: six live enemies; per-def contact_damage/speed/hp, optional hp_mult/hall_dps_mult/targets_crops/spawn_rule)enemy_registry.gd (live_defs/get_def) -> game_root spawn paths (_spawn_enemy_at applies hp_mult/hall_dps_mult/targets_crops; _maybe_spawn_thornrat/_maybe_spawn_torchbearer; _advance_cave_spawns picks ore_tick when world.has_ore_within), simple_threat (targets_crops -> world.nearest_crop/world.eat_crop crop harasser; FQ-13P1 _select_sprite picks one enemies variant pool sprite per instance at creation via variant_for(id, spawn_cell, world_seed, pool_size) = posmod(hash("id:cell:seed"), n), fixed for life, recomputed on load so never saved; canonical -> family-tint fallback; drops)
Ancestriesdata/ancestries.jsonancestry_registry.gd -> player.apply_ancestry_effects, shell create form
Progressiondata/progression/*.jsonprogression_registry.gd -> XP awards, base levels, HUD
Shell profile + character-carried stateuser://shell.jsonGameState, game_root carried-state load/apply
World filesuser://worlds/<id>.jsonGameState, SaveManager, shell world list
Shell UI help textdata/world_settings.json ui_helpshell create screen (axis/gen/preset help)
Ancestry detail textscripts/data/ancestry_detail.gd build_panel_textshell create form, smoke
Opening cinematic narrative (FQ-09C)scripts/shell/prologue.gd SCENES (id, phase, duration, overlay text, audio cue, animation cues; exact copy locked by docs/OPENING_STORYBOARD.md)prologue controller tick clock/text/audio, smoke
Opening cinematic imagery (FQ-09C + authored cels)scripts/shell/prologue_canvas.gd build_commands(scene, tick) remains the deterministic 640x360 fallback; authored pools live under art/generated/opening/prologue.gd prefers authored scene pools when present and returns to the plotted SubViewport path when absent; smoke fingerprints both contracts
Opening puppet acting (FQ-09C)scripts/shell/prologue_puppets.gd — static articulated-figure renderer + keyframe tracks (angles quantized to 5°, pixels snapped)prologue_canvas.gd scene functions
Opening cel-shot hook (FQ-09C)BlockRegistry.visual_variant_textures("opening", scene_id) — FQ-09V <id>_01.png convention or explicit array in data/visual_assets.json; current coverage is eight scene pools / ten PNGs (three frames for opening_01_first_star, one for each remaining scene); empty pool = plotted fallbackprologue.gd (pool loops at 8 fps for the scene; one frame is static)
Action effects (FQ-09M)scripts/fx/action_fx.gd — five deterministic self-freeing kinds, stepped 10 Hz, "action_fx" group, spawn(parent, kind, at[, tint])player.gd (place/cast/hurt/respawn), simple_threat.gd (hit/death), game_root._craft_confirm_fx (forges + hand craft); transient, never saved
Tool swing (FQ-09M)player.swing_phase() — 0/1/2 six pose-steps/s from mining progress, -1 idle; drawn in player._draw with pick/axe glyphpresentation only; mining timing/drops pinned by unchanged baselines
Adaptive music runtime (FQ-09U1)data/music_manifest.json via scripts/audio/music_manifest.gd -> scripts/audio/adaptive_music_director.gd (scenes/audio/AdaptiveMusicDirector.tscn in Main); "Music" bus created at runtimeone AudioStreamInteractive, four named context clips, any->clip next-bar same-position crossfades (crisis entry next-beat); reads is_night/storm_active/current_threat_severity/health ratio/cave-spawn underground rule + the settlement updated signal; transient — never saved
Music context state machine (FQ-09U1)adaptive_music_director.evaluate(state, delta) — deterministic; priority crisis > underground > surface_night > surface_day; pressure = max(threat/40, load/100, 1-health)+storm 0.15; hysteresis 0.60/2s enter, 0.35/6s exit; 1-bar min hold; no re-requests0.5 s poll in _process; smoke drives it directly with synthetic snapshots
Stem layer bed (FQ-09U2)music_manifest.json stems + stem_mix (per-stem source/min_db/max_db, smoothing_db_per_sec 6, storm_pressure_floor_db -16; validator-enforced) -> MusicManifest.load_stem_streams -> AudioStreamSynchronized on the LayerPlayer, same-frame start with the context stream (phase-locked by construction), loop lengths runtime-validated to 53.333 s ±0.05volumes lerp toward targets from settlement resilience/coherence (cached updated signal), pressure score (+storm floor), player attunement ratio, mining/movement activity, collapse edge (pressure>0.7); any failure disables layering only — context music unaffected; transient, never saved
Event stingers + ducking (FQ-09U3)music_manifest.json stingers (five kinds: dawn/nightfall/raid_warning/attunement/base_advance) + stinger_config (duck_db -9, attack/release dB per sec, cooldown_seconds 8) -> MusicManifest.load_stinger_streams -> adaptive_music_director.play_stinger(kind) on the SFX-bus StingerPlayer with a per-frame Music-bus duck envelopewired (deferred) to game_root.music_event(kind) + player.attunement_pulsed; per-kind cooldowns; the bed dips under the stinger, music never stops; transient — never saved
Audio settings (FQ-09U3)scripts/audio/audio_settings.gd — the single bus-volume authority; apply(profile[, duck_db]) creates the Music + SFX buses at runtime and sets volumes from profile keys music_volume/sfx_volume (linear); set_music_volume/set_sfx_volume persist to the profileshell title Music/Sound sliders and the director; profile-level preference, never a world-save key; director process_mode = ALWAYS keeps score + duck ticking under pause
Player body art + rig (art integration)data/player_visuals.json (16x32 bodies, default/female variants, per-species skin palettes + regions, default_rig, gear/swing overlay conventions) + data/character_data.json appearances (skin/trim palettes) -> scripts/player/player_visual.gdPlayerVisual loads a canonical plus two authored Looks for every current body and applies constrained appearance recolor. Authored coverage is 30 static crude-armor overlays (helmet/torso/feet across ten bodies) plus 90 three-phase tool overlays (basic pick, forged pick, crude axe across ten bodies); resolution remains body-specific -> generic -> rig-aware procedural fallback. Intermittent load/refresh alignment is a known visual defect.
Town Hall + world-anchor art (art integration)art/generated/structures/town_hall.png (56x48) + art/generated/blocks/town_hall_core.png (16x16) + art/generated/backgrounds/* strips, all nearest-filteredscripts/settlement/town_hall.gd draws the Hall at Rect2(-28,-48,56,48) with the procedural Hall as fallback (damage overlay preserved); scripts/world/world_backdrop.gd uses native strip sizes with Camera2D zoom as the sole 2x scale; validator art contracts (SHA-checked sizes)
Scenic backdrop (FQ-09W)scripts/world/world_backdrop.gd — code-drawn sky/far/mid planes, stepped parallax, light_mask 0; optional art/generated/backgrounds/ hooks (surface_sky, surface_far_terrain, surface_mid_silhouette)world scene (z -10); cosmetic only, never saved/collides
Natural backing walls (FQ-09W)derived each world.setup from pristine gen.surface + generation.dirt_depthdirt_wall band then stone_wall; tileset has 0 physics / 0 occlusion layers; optional art/generated/back_walls/ tiles else darkened block texturesBackgroundWalls TileMapLayer (z -2); world.wall_at(cell) visual-only query; never in cells/deltas/saves
Column skylight + cave ambient (FQ-09W)world.sky_line(x) (first solid y in LIVE column, cached, invalidated per column on block change) -> game_root.ambient_darkness_factor() / ambient_target_color() (CAVE_TINT, CAVE_FADE_CELLS 6)the CanvasModulate tint lerp in _advance_time and the instant set in apply_time_state; documented approximation — player-column roof-awareness, no lateral bleed
Title/authorship/tagline text (FQ-09C)prologue.gd consts TITLE_TEXT / AUTHORSHIP_TEXT / TAGLINE_TEXTcinematic title card and shell_ui._show_title (single source, cannot drift)
profile.prologue_seen (FQ-09C)user://shell.json profile via GameState.mark_prologue_seen() (idempotent; written only on completion or skip)shell_ui._ready clean-profile autoplay gate

All registries load through scripts/data/json_data.gd (load_dict, push_error + {} on failure).

Current Presentation Defects

SurfaceCurrent truthNext verification target
Equipped character artEquipment state/effects persist, but a matching body-specific overlay can intermittently fail to appear or align after some character/load transitions. The rig-aware fallback prevents a gameplay failure.Reproduce across all ten body ids, save/load, world transitions, and newly forged gear; assert overlay resolution and force a visual refresh at the authoritative state boundary.
Tool and weapon swingBasic/forged pick and crude axe have three authored phases per body. They currently snap between poses; anchors, mirroring, timing, and arc continuity need polish. The sword has no equivalent authored attack sequence.Capture left/right swings for every body at all phases, then add a sword sequence without changing mining/combat timing.
HUD chrome and framed panelsThe native JSON dock contract resolves the previous dock overlap/scaling conflict, but the current PNGs are provisional. Some framed panel/capture states still show padding, mask, or oversized opaque-region defects.Replace chrome through docs/wiki/hud_asset_replacement_studio.md, then visually inspect every panel at target window sizes in addition to smoke assertions.

Planned Authority Surfaces (Not Live)

These rows record operator-approved planning authority. (The FQ-09C opening cinematic and the FQ-09W backdrop/backing-wall/ambient planes are live — see the authority table above; docs/ART_DIRECTION_AND_CANON.md, docs/OPENING_STORYBOARD.md, and art/source_templates/BACKGROUND_TEMPLATE.md remain the style/copy/asset authorities for them and for later art.)

Planned surfacePlanning authorityIntended consumer
Canon, tone, terminology, palette rolesdocs/ART_DIRECTION_AND_CANON.mdasset prompt packs, later public/game writing
Asset map: every live/planned id, path, size, priority, prompt packdocs/ASSET_ROADMAP.md (FQ-09A; validator phrase-locked)human/LLM art passes; no machine manifest exists by decision
Adaptive music program: contexts/stems/stingers, state model, hysteresis, gatingdocs/WORK_ORDER_FQ_09U_ADAPTIVE_MUSIC.md + audio/source_templates/MUSIC_TEMPLATE.md (FQ-09U0; operator-approved)Codex (Godot spike, M8str0 M8-AUDIO-01..03), music-authoring LLM, FQ-09U1..U3 implementation
Music machine contract: grid, contexts, priority, transitions, pressure norms, thresholdsdata/music_manifest.json (validator-checked: 72/4/16 grid, 4 contexts, crisis hysteresis)Live scripts/audio/music_manifest.gd -> scripts/audio/adaptive_music_director.gd; smoke exercises context selection, transition timing, stems, stingers, and ducking
Constructed (player-placeable) backing wallsart/source_templates/BACKGROUND_TEMPLATE.mda later bounded gameplay task — needs wall deltas, drops, recipes, save ownership/migration decisions
Cave/deep background layers (cave_far, deep_cavern_far) and wall variants beyond dirt/stoneart/source_templates/BACKGROUND_TEMPLATE.mdFQ-09A asset roadmap; runtime wiring when those environments exist

Scenic backdrops, natural backing walls, and foreground cells are separate planes (live as of FQ-09W). No wall dictionary or wall delta is a live save authority: natural walls are deterministic/derived; player-placeable walls require a later explicit save ownership and migration decision.

v0.6 Ownership Boundary

StateOwnerNotes
Inventory counts, hotbar slot, tool tiers {pick, axe}character (user://shell.json)carried_inventory, carried_slot, carried_tool_tiers, legacy carried_tool_tier alias
Gear slots (FQ-03/FQ-04/FQ-11)character (user://shell.json)equipment dict (12 slot_id -> item_id, "" = empty); pickaxe/axe slots derive from live tool tiers at save time; weapon and crude/iron armor acquisition and effects are live; rings, amulet, and accessory persist even where gameplay effects or authored presentation remain limited; pre-FQ-03 characters gain the dict on migration
Role starter itemscharacteritems_granted flag; granted once per character
Terrain, hall stockpile, time, threats, storms, settlementworld fileunchanged
Player position, healthworld fileentering character inherits world position/health
XP totals, player level, base level/XPworld fileexplicit v0.6 decision; revisit for cross-world leveling
Legacy migrationone-timecharacter without carried_inventory adopts world save's player keys once; legacy tool tier -> {pick: N, axe: 0}

World Config Matrix

Config keyConsumed byEffect
sizeWorldConfig.size_dims, WorldGen.generate, world.world_bounds, camera limitssmall 160x64, medium 240x80, large 360x100
seedWorldGen.generatedeterministic base terrain
generation.terrain_amplitudeWorldGen.generatesurface height variation
generation.terrain_frequencyWorldGen.generatesurface noise frequency
generation.dirt_depthWorldGen.generatedirt layer depth before stone/ore
generation.ore_abundanceWorldGen.generateore threshold; 0 disables ore
generation.ore_seed_offsetWorldGen.generateindependent ore layout channel
generation.tree_densityWorldGen.generatetree site frequency; 0 disables trees. FQ-09R: every site grows one unified tree (tree_trunk column + tree_leaves canopy), walk-past and harvestable. The FQ-02 tree_foreground_ratio key/slider is removed (stored copies in old world configs are ignored)
generation.tree_seed_offsetWorldGen.generateindependent tree channel
generation.bush_densityWorldGen.generateberry bush frequency; 0 disables bushes
generation.bush_seed_offsetWorldGen.generateindependent bush channel
difficulty.enemynight_spawn_count, threat_hp, threat hall_dpsnight threat count, hp, hall damage
difficulty.rulersettlement_model.gather_inputspopulation pressure multiplier
difficulty.survivaldaily_food_needfood demand multiplier
difficulty.economysettlement_model.gather_inputsstockpile/scarcity scaling
difficulty.socialstored onlyreserved for social simulation
difficulty.impressionabilitygrowth_thresholdlower threshold means easier population growth
environment_dangerstorm roll and storm dpsstorm frequency/damage multiplier
rules.subjects_require_foodfood consumption, starvation, scarcity, growth gatedisables/enables food pressure
rules.weather_affects_survivalstorm roll and force_stormdisables/enables storms
rules.lighting_affects_safetynight_spawn_counttorch light can reduce night spawns
rules.darkness_increases_enemiesnight spawns and threat severitydisables/enables night threats
rules.enemies_scale_over_timethreat_hpthreat hp grows with day count
future rule togglespersisted onlysleep, sickness, morale, loyalty, rebellion, ruler pressure growth, scarcity growth

Character Matrix

Character keyAuthorityConsumed byEffect
nameshell create form / shell.jsonshell listsdisplay identity
speciescharacter_data.json + ancestries.jsonshell create form, game_root.apply_ancestry_for_specieslive phase B ancestries: human, dwarf, elf, goblin, orc; effects re-derived from data at world entry
appearancecharacter_data.jsonplayer.apply_characterbody/trim draw colors
traitscharacter_data.jsonplayer.apply_charactermax health, mining speed, reach, food bonus, growth delta
rolecharacter_data.jsonrole grant and player.apply_characterstarting items and role effects

FQ-01 Player Defaults (Health, Healing, Collapse)

VariableFile / FieldDefaultEffect
base_max_healthdata/character_data.json player_defaults.base_max_health100base max health before trait/role/ancestry bonuses (player._base_max_health)
hurt_cooldown_secdata/character_data.json player_defaults.hurt_cooldown_sec0.8i-frame window after take_damage; blocks re-damage until it expires
food_heal_amountdata/character_data.json player_defaults.food_heal_amount25health restored per food eaten (clamped to max_health)
eat_cooldown_secdata/character_data.json player_defaults.eat_cooldown_sec0.5minimum time between eat_food actions
passive_regen_per_secdata/character_data.json player_defaults.passive_regen_per_sec1.0health/sec regenerated near the Town Hall when safe
safe_radius_pxdata/character_data.json player_defaults.safe_radius_px160distance from hall center within which passive regen can trigger
collapse_loss_fractiondata/character_data.json player_defaults.collapse_loss_fraction0.25fraction (floored per stack) of carried inventory lost on collapse (health reaching 0)
low_health_fractiondata/character_data.json player_defaults.low_health_fraction0.25health/max_health ratio below which the HUD tints red and logs "You are badly hurt." once per crossing

All eight keys are read once via player._load_player_defaults() from BlockRegistry.character_data["player_defaults"] (same JSON-load pattern as traits/roles/appearances); missing keys fall back to the DEFAULT_* consts in player.gd.

FQ-05 Attunement (Player Magic Resource)

VariableFile / FieldDefaultEffect
base_max_attunementplayer_defaults.base_max_attunement50base of the computed player.max_attunement()
attunement_regen_per_secplayer_defaults.attunement_regen_per_sec2.0constant regen everywhere (no safety gate), scaled by ancestry attunement_regen_mult
attunement_pulse_costplayer_defaults.attunement_pulse_cost15attunement spent per light pulse (attune_pulse action, R)
attunement_pulse_cooldown_secplayer_defaults.attunement_pulse_cooldown_sec1.0pulse re-cast gate
attunement_pulse_duration_secplayer_defaults.attunement_pulse_duration_sec4.0pulse light fade time
player.attunementplayer.gd / world save (player.attunement)fullcurrent pool; world-saved next to health; pre-FQ-05 saves default to full
player.max_attunement()player.gd (computed)50base + ancestry attunement_bonus + gear attunement_bonus sum; perks join here at FQ-06
attunement_bonus / attunement_regen_multdata/ancestries.json player_effects (hooks; no live ancestry sets them yet) + data/equipment.json item effects (amulet_focus = +10)0 / 1.0ancestry additive max + regen multiplier; gear additive max

Extension points documented in docs/FUTURE_PROGRESSION_RESEARCH_AND_BASE_LEVELS.md ("Attunement Extension Points"). A non-magic character never spends or needs attunement; nothing existing is gated by it.

Health, Healing, And Collapse

Two healing sources are wired in FQ-01: eat food (active, bound to the eat_food input action — key H — consumes 1 food from the inventory for an instant food_heal_amount heal, no-op at full health or during its own cooldown) and safe passive regen (near the Town Hall center within safe_radius_px and clear of any "threats" group node within 200px, health trickles back at passive_regen_per_sec; logs "You feel safe near the Town Hall and begin to recover." once per regen streak). Damage still gates through the existing hurt_cooldown_sec i-frame window and flashes the player sprite red for ~0.2s. Reaching 0 health triggers a collapse: each carried inventory stack loses floor(count * collapse_loss_fraction) (deterministic, per stack) before the player respawns at the Town Hall at full health, with the log message "You collapsed and awoke near the Town Hall. Some of your supplies were lost." Crossing below low_health_fraction of max_health logs "You are badly hurt." once per crossing and tints the HUD health bar/label; it resets when health rises back above the threshold.

Core Gameplay Variables

VariableTypeAuthorityNotes
tile_sizeintdata/blocks.json16 px
block_idstringdata/blocks.jsondirt, grass, wood, stone, ore, tree_trunk, tree_leaves, berry_bush, torch, lantern, town_hall_core, air
tree_trunk / tree_leavesblocksdata/blocks.jsonFQ-09R unified trees: both non-solid (walk in front of/past, no occlusion) and non-placeable; trunk = wood hardness 0.55, axe-preferred, drops 1 wood; leaves = hardness 0.15, no drops. Generated into cells like any block; mined cells persist as normal air deltas
hardnessfloatdata/blocks.jsonmining time input
required_tool_tierintdata/blocks.jsonore requires tier 2 (pick tier)
preferred_toolstringdata/blocks.jsonaxe: wood, berry_bush; pick: stone, ore; axe-preferred mine 1.4x faster with an axe
requires_supportbooldata/blocks.jsonberry_bush; enforced on mine, load sweep, and regrowth
axe_tierintplayer.gd / character-carried0 = no axe; craft_axe recipe (4 wood + 2 stone, town_hall) sets 1
equipment (slots)datadata/equipment.jsonFQ-03: 12 slots (weapon, axe, pickaxe, helmet, torso, feet, ring_1-4, amulet, accessory) with accepts slot_type; validator-enforced
equipment (items)datadata/equipment.jsonitem defs {display_name, slot_type, description, effects}; live: pick_basic (pick_tier 1), pick_forged (pick_tier 2), axe_crude (axe_tier 1), sword_crude (attack_damage 3), helmet_crude/torso_crude/feet_crude (armor 1/2/1); inert: ring_band
attack_damageint effectdata/equipment.json -> player.attack_damage()FQ-04: melee damage per hit from the equipped weapon; 1 bare-handed; consumed by _try_hit_threat -> threat.take_hit
armorint effectdata/equipment.json -> player.armor_total()FQ-04: flat incoming-damage reduction summed over ALL equipped items (helmet/torso/feet today); applied in take_damage with a minimum 1-health chip per landed hit
craft_sword / craft_armor_setrecipesdata/recipes.jsonFQ-04: town_hall station, empty outputs; consumed by town_hall.forge_sword/forge_armor which equip gear via player.equip_item (guards: weapon/torso slot must be empty)
player.equipmentdictionaryplayer.gd / character-carriedslot_id -> item_id for the 10 non-tool slots; equipped_dict() merges in pickaxe/axe derived from live tiers; equip_item(slot, item) validates fit via BlockRegistry.item_fits_slot; tool slots cannot be cleared (tiers come from forging)
dropsdictionarydata/blocks.jsoninventory additions on break
is_placeablebooldata/blocks.jsonplacement gate
is_solidbooldata/blocks.jsoncollision, shelter, roof, defense
blocks_lightbooldata/blocks.jsonruntime occluder polygons
emits_lightbooldata/blocks.jsonruntime PointLight2D nodes
light_radiusintdata/blocks.jsontorch/lantern radius
settlement_tagsarraydata/blocks.jsonprotected, defense
world_seedintworld file statedeterministic terrain regen
terrain_deltasdictionaryworld file stateedits over regenerated terrain
world.width/heightintWorldConfig.size_dimsreplaces old constants
surfacedictionaryWorldGen.generatetop solid y per x
hall_infodictionaryWorldGen.stamp_town_hallcenter cell, ground y, protected core cells
bush_regrowdictionaryworld.gd / saveharvested bush timers
player_positionVector2save staterestored after world rebuild
player_healthfloatplayer.gd / saveHUD and threat damage
player.max_healthfloatplayer.gdplayer_defaults.base_max_health + trait/role/ancestry bonuses; recomputed by apply_character/apply_ancestry_effects, not persisted directly (derived at world entry)
inventory_countsdictionaryinventory.gd / character-carriedstackable resource counts; travels between worlds
selected_hotbar_slotintplayer.gd / character-carriedslots 1-5
tool_tierintplayer.gd / character-carriedpick tier alias; tier 2 unlocks ore and speed
effective_mine_speedfuncplayer.gdtool tier, trait, and FQ-06 perk multiplier
mine_damage_stage()funcplayer.gdFQ-08: 0-3 from mining progress; drives the transient crack overlay drawn on the target cell; never saved; resets via _reset_mining (target change, release, and on load via apply_state). Cracks rasterize through world.block_opaque_mask so they never draw outside the sprite
block_opaque_mask(block_id)funcworld.gdcached BitMap of a tile texture's opaque pixels (art or generated fallback; null for air/unknown); consumed by the crack overlay so degradation stays inside the visible sprite (thin trunks, leaves, bushes, torches)
health_bar_ratio()funcsimple_threat.gdFQ-08: hp/max_hp fill for the mini hurt bar drawn above damaged enemies on both art and fallback paths
reach_bonusfloatcharacter effectsextends mining/placement reach
bush_bonus_foodintcharacter effectsextra food from berry bushes
growth_threshold_deltafloatcharacter effectsmodifies settler growth threshold
town_hall_stockpiledictionarytown_hall.gd / saveresources deposited at hall
town_hall.damagefloattown_hall.gd / save0-100 damage
population_countinttown_hall.gd / savedynamic 1-8
day_countintgame_root.gd / saveHUD day
time_of_dayfloatgame_root.gd / save0-1 over 100 seconds
is_nightboolderivednight begins at 0.65
storm_activeboolgame_root.gd / savecurrent storm state
storm_time_leftfloatgame_root.gd / savecountdown
_storm_rolled_todayboolgame_root.gd / saveprevents repeated daily storm rolls
threatsarraysave statesaved/restored active threats: x, y, hp, max_hp, enemy_id; restored via _spawn_enemy_at
meta.summarydictionaryworld fileday, population, coherence, damage for shell list

v0.5 Enemy Variables

VariableTypeAuthorityNotes
enemy_id / familystringdata/enemies.jsonlive: surface_slime (surface), cave_crawler (underground), raider_basic (raider)
drops[].item_id / .chancearraydata/enemies.jsonrolled on death into player inventory
spawn_rule (raider)dictionarydata/enemies.jsonday_threshold 5, stockpile_threshold 25, base_chance 0.3
difficulty_scaling.density_multfloatdata/enemies.jsonmultiplies night spawn count and raider chance
difficulty_scaling.loot_multfloatdata/enemies.jsonmultiplies drop chances
loot_mult / drop_chance_overridefloatsimple_threat.gdper-instance; override is a test hook
hall_dpsfloatgame_root._spawn_enemy_atraider Town Hall damage; survives save/load
CAVE_SPAWN_INTERVAL / capconstgame_root.gd30s check, 2 active underground-family max
contact_damagefloatdata/enemies.json (live enemies) -> simple_threat.contact_damageplayer damage on contact; scaled by difficulty("enemy") at spawn (mirrors hall_dps); falls back to PLAYER_DAMAGE const if the def omits it
speedfloatdata/enemies.json (live enemies) -> simple_threat.move_speedhorizontal chase speed; falls back to SPEED const if the def omits it
hpintdata/enemies.json (live enemies)data-completeness/validator field; runtime hp is still set from game_root.threat_hp() (difficulty + day scaling), not read from this field

FQ-06 Perk Variables

VariableTypeAuthorityNotes
perk node schemadatadata/progression/perks.json7 lanes x 3 nodes; each node: id, display_name (title), description, effect_key, effect_value, cost, position [x,y], prerequisites (same-lane ids), xp_type_gate; validator-enforced
purchased_perksArray[String]game_root.gd / world save (progression.purchased_perks)world-owned like XP/levels; unknown ids dropped on load (silent refund)
perk pointsderivedgame_root.perk_points_total/spent/availableone point per player level above 1; spent = sum of purchased costs
perk_state(id)funcgame_root.gd"purchased" / "available" (prereqs owned) / "locked"; affordability gates only purchase
player.perk_mine_speed_multfloatgame_root._apply_purchased_perk_effects -> player.apply_perk_effectslive effect_key mining_speed (Miner lane); multiplies effective_mine_speed
player.perk_attunement_bonusfloatsamelive effect_key attunement_bonus; the FQ-05 join point inside max_attunement() (no node carries it yet)
planning effect keysdata-onlydata/progression/perks.jsondetect_ore_range, cave_safety, and all non-miner lane keys stay inert until their systems ship
skill tree panelUIscripts/ui/skill_tree_panel.gd (K, toggle_skills)scrollable node canvas from data positions; locked/available/purchased colors + [OWNED]/[LOCKED] markers; inspector + learn button; joins the Esc close chain ahead of inventory. FQ-09S: night-sky backdrop, deterministic starfield, constellation link lines per prerequisite pair (link_count() hook), star glyphs, state-colored plaques — presentation only, inspector format and purchase path unchanged

v0.5 Progression Variables

VariableTypeAuthorityNotes
xp_totalsdictionary (float)game_root.gd / saveper-type fractional accrual; int() at read points
player_levelintgame_root.gd / save100 * 1.35^(n-1) curve from player_xp.json
base_levelintgame_root.gd / saveratchet 1-3 (MVP cap); one tier per check; fail-closed requires
base_xpintgame_root.gd / saveinformational only
_depth_hwmintgame_root.gd / save10-tile depth bands for exploration XP
effective_population_cap()funcgame_root.gdbase level's unlocks.population_cap clamped to POPULATION_MAX (camp 4, hamlet 6, village 8)
xp_eventsdatadata/progression/player_xp.json9 events wired: enemy_defeated, block_mined, block_placed, resource_deposited, storm_survived, night_survived, subject_fed, tool_crafted, new_depth_reached

v0.5 Ancestry Variables

VariableTypeAuthorityNotes
ancestry_move_mult / ancestry_jump_multfloatdata/ancestries.json -> player.gddwarf 0.9/0.85; elf jump 1.15 (from jump_bonus)
stone_ore_mine_multfloatsamedwarf 1.2 on stone/ore blocks
ancestry_health_bonusintsameorc +25
health_reductionfloatsamegoblin 0.8x max health (multiplicative, after bonus)
learning_speed_multfloatsamehuman 1.05x on all award_xp amounts
phase_b_ids()funcancestry_registry.gdderived from implementation_phase == "B" in data

C/L/R Inputs

InputAuthorityNotes
shelter_scoresettlement_model.gather_inputsnearby solid blocks, cap 30
light_scoresettlement_model.gather_inputsnearby light blocks, cap 30
stockpile_scoresettlement_model.gather_inputstotal stock adjusted by economy difficulty
defense_scoresettlement_model.gather_inputsnearby defense-tagged blocks
damage_scoresettlement_model.gather_inputsTown Hall damage pressure
threat_scoregame_root.current_threat_severitynight/storm/live threat severity
scarcity_penaltysettlement_model.gather_inputstotal stock and food shortage pressure
population_pressuresettlement_model.gather_inputspopulation versus stockpile, scaled by ruler difficulty

coherence, load_value, and resilience are formula outputs from data/settlement_rules.json, clamped to 0-100.

Validation Hooks

FQ-11 adds 7 checks (fq11_*, suite total 269) covering: station gating (a station recipe is locked until its station is built, and a station cannot be built before its prerequisite); the workbench -> furnace build chain spending build costs from the stockpile; the furnace smelting raw ore + coal into an ingot placed in the stockpile (not the player's inventory); the anvil forging the iron sword from ingots (equipped, attack 5); the metal gate (with only raw ore and no ingots, the anvil cannot produce the sword); the bronze alloy (copper + tin ingots -> bronze at the furnace); and stations_built round-tripping through save/load. validate_repo.py additionally enforces the workbench->furnace->anvil prereq chain, that furnace smelt recipes consume ore and output ingots to the stockpile, that no anvil recipe consumes raw ore (the metal gate) and each equips a real gear item into the right slot, and that the iron gear exists and out-damages the crude tier.

FQ-10 adds 5 checks (fq10_*, suite total 262) covering: the six ore families all generating at meaningful counts in a large rich world (coal/ copper/tin shallow, iron mid, silver+crystal deep); the generic starter ore vein surviving alongside them; deterministic ore-family layout across two same-seed setups (never saved); the tier gate (iron behind the tier-2 pick, coal minable at tier 1); and ore_abundance 0 clearing every ore — families and generic vein alike. validate_repo.py additionally requires the six ore blocks (self-drop, pick-preferred, tier 1..2, deeper ores held at tier 2) and the ore_table contract (each entry a real block, valid depth band, threshold in (0,1), positive frequency, unique seed_offset).

FQ-09U3 adds 8 checks (fq09u3_*, suite total 257) covering: the five stinger OGGs loading as non-looping one-shots under 8 s with the director reporting all five kinds; a fired stinger ducking the Music bus below -3 dB while the context loop keeps playing (the stinger itself rides the SFX bus, so the duck lowers the bed UNDER it, never the stinger); the duck envelope releasing back toward 0 dB after the stinger ends; per-kind cooldowns blocking a repeat while allowing a different kind and then the same kind after the cooldown; the game-event surface reaching the director — music_event("nightfall") and the player's attunement_pulsed each fire their stinger (the deferred-wiring fix: the director connects these in a call_deferred _wire_events so game_root's @onready player is live by then); music/SFX volume settings applying to the runtime buses via AudioSettings from profile-level keys (music_volume/sfx_volume) and round-tripping; and the world save carrying zero music/volume/stinger keys. AudioSettings.apply(profile[, duck_db]) is the single bus-volume authority (Music and SFX buses created at runtime); stinger timing/duck numbers live in the manifest's stinger_config (duck_db, duck_attack_db_per_sec, duck_release_db_per_sec, cooldown_seconds). The director's process_mode = ALWAYS keeps the score breathing and the duck/cooldown envelope ticking through pause. This run also landed the concurrent Codex art integration (55 generated PNGs: blocks, items, enemies with variants, ten player bodies, Town Hall, backgrounds, back walls) plus its runtime wiring (data/player_visuals.json, scripts/player/player_visual.gd, Town Hall/backdrop nearest-filtering and sizing); those surfaces carry their own validator art-contract checks.

FQ-09U2 adds 8 checks (fq09u2_*, suite total 234) covering: the mandated nesting spike executed live and its finding recorded (Synchronized-inside-Interactive PLAYS in 4.6.1; the parallel LayerPlayer design ships regardless since the suite has one shared stem set); the stem bed live — six loops at the exact grid length on the Music bus; targets following settlement coherence/resilience; the pressure stem and the collapse-edge-only fracture stem; the storm texture floor; smoothing verified to the decimal (-40 -> -37.00 dB at 6 dB/s over 0.5 s, never snapping); a deliberately length-mismatched stem set disabling layering while the context stream plays on; and save round-trips carrying zero stem/music keys with the bed surviving load. validate_repo.py additionally requires the six stem OGGs and the manifest's stem_mix contract (all six layers, min<=max dB, positive smoothing rate).

FQ-09U1 adds 9 checks (fq09u1_*, suite total 226) covering: the manifest loads with all four context loops decoded and the 72/4/64 musical grid stamped onto every stream; the director is live on the runtime-created Music bus with a four-clip AudioStreamInteractive; night/dawn/underground resolution from clean baselines; crisis enter hysteresis (a brief spike never enters, sustained 2 s does); crisis exit requiring both the lower threshold and the 6 s delay; identical states never re-request the current or pending clip; the LIVE spike proof that a next-bar same-position crossfade actually reaches the requested clip during real playback (get_current_clip_index); missing assets disabling audio silently while the state machine keeps evaluating; and save round-trips carrying zero music keys with the director surviving load. All state-machine checks call evaluate(state, delta) directly with synthetic snapshots — no wall-clock dependence. validate_repo.py additionally requires the director script/ scene, the manifest loader, the Codex render/verify tooling, the m8patch, and the four context OGGs.

FQ-09M adds 7 checks (fq09m_*, suite total 217) covering: the swing phase tracks mining state (idle -1, active >= 0, back to -1 on reset); placing a block spawns exactly one placement pulse; the attunement cast spawns its ring at the fire moment; a landed player hit sparks and a collapse adds fall-and-respawn dust; enemy hits spark (hp/drops behavior stays pinned by the fq08 checks); a successful hand craft fires the shared confirmation burst (the four forge handlers use the same _craft_confirm_fx path); and every effect self-frees within its lifetime, so the "action_fx" group returns to empty — transient by construction, nothing can reach saves. validate_repo.py additionally requires scripts/fx/action_fx.gd.

Separately in the same run, the Codex lane's scripts/audio/verify_music_assets.py mechanically verified the FQ-09U asset suite (loop sample counts, stinger lengths, stem-combination headroom); it is Codex-lane tooling, not part of the Godot smoke.

FQ-09W adds 7 checks (fq09w_*, suite total 210) covering: the natural wall map is identical across two same-seed setups with the dirt band above stone, nothing at/above the surface row, and a wall tileset carrying zero physics and zero occlusion layers (structurally unable to affect collision, lighting, shelter, or settlement math); a mined below-surface block stays a normal air delta while wall_at still reports the wall behind it; at midday the underground ambient target reaches the cave tint while the surface stays exactly DAY_TINT (asserted on ambient_target_color, not the smoothing lerp); a freshly mined open shaft admits daylight to its floor while a sealed column at the same depth stays dark (live column skylight); the backdrop node sits behind the walls layer which sits behind the Blocks layer, with null image hooks falling back to code-drawn planes; a dropped-in back_walls PNG resolves through the registry and removal falls back (self-cleaning temp art); and the saved world restores cleanly afterwards. validate_repo.py additionally requires world_backdrop.gd, the backgrounds/back_walls categories, and their art directories. The screenshot tour adds 09_underground_midday_torch.

FQ-09C adds 13 checks (fq09c_*, suite total 203) covering: the smoke run itself proves the COHERONIA_SMOKE bypass (no prologue node in the tree); exact scene order and overlay copy walked live scene by scene; the title card's three exact engine lines including By Paul Peck; completion emits finished(true) exactly once with no double-advance past the end; skip finishes safely mid-sequence with the tick clock stopped and audio silent; the profile-level seen flag round-trips through a shell reload, is idempotent, and the operator's prior value is restored; a full replay touches no characters or worlds; scene durations/cues are data-driven (42.0s, every scene declares nontrivial animation cues); the authored surface is the locked 640x360 grid at 10 Hz; every scene's draw-command fingerprint changes across ticks (a fade-only scene fails); the same scene+tick always replots identically (determinism); the cel-shot hook (a temp frame pool plays in place of the plotted shot and removal falls back); and the title screen renders the exact title/authorship/tagline labels plus the Prologue replay button alongside intact Play/Continue/Quit wiring. validate_repo.py additionally requires prologue.gd/prologue_canvas.gd/prologue_puppets.gd, all eight opening_NN_ ids in both the storyboard and the runtime, and the exact title lines in the runtime.

FQ-09 adds 4 checks (fq09_*, suite total 183) covering: toolbelt slot tiles show live counts and the gold selected-slot highlight follows the selected slot; the inventory panel's icon grid mirrors injected counts while the panel opens normally; the town stockpile grid mirrors the hall stockpile; and the acceptance flow — grids track counts through mine (+1 dirt), craft (craft_torch: 3 torches appear), deposit (stockpile grid rises; torches are not depositable), and load (grid matches the restored inventory exactly). The FQ-07 hotbar item check was rewritten to art-vs-fallback semantics (hotbar_icon_is_art) because slots now always display an icon.

FQ-08 adds 6 checks (fq08_*, suite total 179) covering: a stone target's damage stage rises from 0 to 1-3 mid-mine; the stage resets on target change and on mining stop; partial damage is transient — it survives neither save nor load, the block stays intact, and finishing the mine still yields exactly one drop; and enemy damage is visible before death (hurt-bar ratio 1.00 -> 0.67 after a non-lethal hit, enemy alive, no drops rolled).

FQ-07 adds 4 checks (fq07_*, suite total 173) covering: visual_assets.json loads with the four categories; missing images return null lookups while generated block textures still render and hotbar icons stay hidden (no crash); a runtime-written block PNG wins over the generated texture and the fallback returns after removal (pixel-verified both ways); and an item PNG lights its hotbar icon then hides on removal. The smoke writes and deletes its own temp art (with leftover cleanup at section start) so the repo stays art-free. validate_repo.py requires visual_assets.json + the art/generated dirs, fails on broken explicit references, and reports convention gaps as INFO.

FQ-06 adds 6 checks (fq06_*, suite total 169) covering: perk data loads with 7 lanes and correct miner prerequisites; at level 1 with nothing purchased the root node is available, its child locked, points 0, and purchase refused; at level 3 (2 points) purchasing stone_recovery succeeds, leaves 1 point, and multiplies effective_mine_speed by exactly 1.15; prerequisites unlock children while the 2-cost node stays unaffordable and re-purchase is refused; purchased perks + level persist through the world save round-trip with the effect re-applied; and the panel opens, selects/inspects nodes (PURCHASED/AVAILABLE states, prerequisite names, description), and closes. The toggle_skills binding joined input_actions_bound; validate_repo.py enforces the perk node schema (fields, unique ids, cost >= 1, [x,y] positions, same-lane prereqs).

FQ-05 adds 6 checks (fq05_*, suite total 163) covering: data-driven defaults (max 50); the pulse spends exactly its cost, lights up, and respects its cooldown; insufficient attunement blocks the pulse without spending; attunement regenerates over time; ancestry (attunement_bonus 20 -> max 70, attunement_regen_mult 2.0) and gear (amulet_focus -> max 80) hooks raise the maximum and removal clamps back to 50; and the current value rides the world save (21.0 round-trips). The attune_pulse binding joined the input_actions_bound list; validate_repo.py requires the five attunement player_defaults keys and the amulet_focus item.

FQ-04 adds 8 checks (fq04_*, suite total 157) covering: bare-handed baseline (attack 1, armor 0); forging the sword equips it, consumes 2 wood + 3 stone, and cannot repeat; one real hit-path strike kills a 3 hp slime; forging the armor set equips helmet/torso/feet (armor total 4) and cannot repeat; a 10-damage hit loses exactly 10 - armor_total(); a 2-damage hit under 4 armor still chips exactly 1 (no immunity); combat gear round-trips through character save/load with ancestry/trait max_health untouched; and the equipment UI shows "Attack 3 · Armor 4" plus the equipped weapon/torso names. validate_repo.py additionally requires the four combat items with meaningful effects and the two forge recipes.

FQ-03 adds 7 checks (fq03_*, suite total 149) covering: equipment.json loads with the 12 expected slots in order; a new character record carries default gear (pick_basic + 11 empty slots); equipped tool slots mirror the live tool tiers both ways; slot/item mismatches are rejected and equipping never touches the backpack; an equipped inert item (ring_band) round-trips through character save/load while empty slots stay valid; the inventory panel shows every gear slot with (empty) placeholders; and a pre-FQ-03 character (no equipment key) migrates with tool tiers and inventory preserved and gear derived from tiers. validate_repo.py additionally enforces the equipment.json schema (slot list, required items, slot_type coherence, tool item tiers).

FQ-09V adds 5 checks (fq09v_*, suite total 190) with self-cleaning smoke_tmp_* temp art: pools resolve through both the <id>_01/_02 file convention and an explicit array entry while a pool-less block reports none; variant selection is deterministic (two setups of seed 777 render identical dirt variants over a 40-cell sample with at least 2 variants in use); a different seed (778) changes the selection somewhere in the sample (nothing is stored); removing the pool falls back to exactly one source with the generated texture; and the live world state is restored afterwards.

FQ-09S adds 1 check (fq09s_constellation_links_match_prereqs, bringing the suite to 185 at that point): the star-map canvas draws exactly one constellation link per prerequisite pair in the live lane, with the expected count derived from the same perk_lanes() data the buttons use — presentation cannot invent or drop an edge. All six fq06_* checks (states, purchase, prereq/cost gates, persistence, inspection text) pass unchanged against the restyled panel.

A post-FQ-09R hardening run adds 1 check (fq08_crack_mask_inside_sprite, suite total 184): world.block_opaque_mask is fully opaque for stone, opaque at the trunk bar but transparent at both tile edges for tree_trunk, and null for air — pinning that the crack overlay's per-pixel mask keeps degradation inside the visible sprite.

FQ-09R replaces the 8 FQ-02 checks with 8 fq09r_* checks (suite total unchanged at 183) covering: tree_density 0 clears trunks and leaves; default generation produces trees with leaves (trunk and leaf counts both > 0); every generated tree cell is non-solid and bare-hand mineable (one tree class — no walk-past-only kind); density 2.0 grows more trunks than default on the same seed; mining a trunk yields exactly 1 wood through the normal drop path and leaves an air delta; clearing a leaf cell changes no inventory count; and the live traversal pair — a surface trunk is found on flat terrain and the player walks past it using only move_right (no jump, no mining). The baseline mining checks (mineable_blocks_found, hardness_orders_mining_time, wave_f_*) now harvest tree_trunk, preserving the dirt < trunk < stone ordering and the axe speed-up on the same wood-hardness value.

FQ-01 adds 8 checks (fq01_*) covering: i-frame damage gating and the post-cooldown hit; eat-food healing (consumes 1 food, clamps to max_health) and its full-health no-op; passive regen near vs. far from the Town Hall; collapse inventory loss (floored per stack) plus respawn-at-hall-at-full-health; health save/load round-trip with max_health preserved; and enemy contact damage read from data/enemies.json scaled by difficulty("enemy").

The v0.6 smoke suite (122 checks) additionally verifies: ancestry detail text (dwarf effects + constraint, planned label for non-live); world_settings ui_help coverage of all six axes and preset deviations; character inventory isolation (two characters, one world; second world; no starter-item duplication; legacy migration); toggle_inventory binding and panel open/close/content; berry-bush support cleanup on mine/load/regrowth; axe crafting, axe-vs-pick speed differentiation (33 -> 24 frames at wood hardness — originally on solid wood columns, harvested from tree_trunk since FQ-09R; stone unchanged), and {pick, axe} save round-trips with legacy tool-tier migration.

The v0.5 smoke suite (90 checks) additionally verifies: enemies.json loads with 3 live defs; each live enemy spawns with its def id; drops enter the inventory; enemy save/load round-trips id/hp/max_hp/hall_dps; progression JSONs load; XP awards accrue (including human fractional bonus 21 vs 20 over 20 events); level curve; base level advances camp -> hamlet; population caps at 4/6/8 by level and growth is gated; underground threats survive dawn while surface threats are freed; peaceful rule blocks cave spawns; ancestry effects (dwarf mults, orc health, goblin reduction, elf jump) and unknown-species baseline.

The v0.4 smoke suite verifies:

  • shell character/world persistence
  • presets and world config overlay
  • role items and character trait effects
  • input bindings
  • movement, jump, mining, drops, hardness order
  • ore/tool-tier gate and tier-2 speed
  • berry food and regrowth
  • farming: till, plant, grow, harvest, no-float/no-regrow, timer save/load, food-yard score
  • placement, torches, occlusion, lanterns
  • deposit, population food use, population floor/cap/growth
  • rule toggles for food, weather, darkness
  • enemy difficulty and impressionability scaling
  • enemy variety (FQ-13): thornrat crop-eating, ore tick near ore, torchbearer hall burn, per-def hp/dps profiles, drops
  • goal panel (FQ-14): state-derived objectives, prefix-latch (no regress), toggle, no save state
  • map/scouting (FQ-15): reveal-on-explore bands, hall/player/ore/threat markers, discovered-band persistence, biome_reveal scouting hook
  • C/L/R reaction to light and threats
  • storm pressure, damage, and roof mitigation
  • save/load of player, terrain, stockpile, lights, threats, tool tier, regrow timer, crop-growth timers, storm state, discovered map bands
  • world size, ore abundance, density controls, and per-block seed variation

Required Audit Behavior

After implementation runs, update this file when variables are added, removed, renamed, or moved between authority surfaces. A run is not SIGNABLE if C/L/R values are decorative or disconnected from world state.