### 📎 Feedback: Real Engine-Log Attachments
- Crash reports were uploading the **wrong** log — the prompt runs after Godot renames the old log to a timestamped file, but the code read the path for the *current* session. New `LogFile.gd` reads the previous session's log for crash reports, the current one for bug reports.
- Log tail moved out of the bug-description text field into its own `log_tail` column; attach-log is opt-in and off by default (may contain local paths).
### 🔎 SIGSEGV Hunt (temporary instrumentation)
- `CrashTrace.gd` writes and flushes one line per checkpoint — Godot's own log buffer loses its tail on a native crash.
- Prime suspect is now the **fog veil** (added in 1.9.2), not the recipe system: the first crash log lands the same day the feature shipped.
- Log rotation raised to 50 files (was 5) so repro logs stop rotating away.
### ☁️ Supabase Uploads Restored + Retry Queue
- `run_stats`/`leaderboard` uploads had been silently failing since a prior migration was never applied. New `UploadQueue` autoload persists failed uploads to disk and retries them.
- Fix: a restored pending upload round-tripped through `JSON.parse()`, which turns every number into a float (`4` → `4.0`) and got rejected by Postgres — and since retries always tried the oldest item first with no drop-on-failure, one bad legacy entry blocked every later upload forever. Payloads now store as a pre-serialized string; non-retryable 4xx responses are dropped instead of retried forever.
- Leaderboard row-height measurement could crash on a freed node if a resize landed mid-measurement; now queues and replays instead of racing.
### 💾 Autosave After Draft
- A crash in round 1 used to cost the whole draft, since autosave only fired after a wave was cleared. Now saves right after the draft completes.
### ↩️ Undo: POI Restore on Consumed Placement
- Placing a card on a tile whose POI was already used deleted the POI permanently instead of letting Undo bring it back — now restored correctly.
### 🐛 Small Fixes
- Sacrificial Site's destroy-tile choice text was missing a format argument (literal `%d` on screen).
- Bramble's zone can no longer target the base tile.
- Quest label kept a literal `%d` after save/load; Deck Restoration button now shows a checkmark instead of "16/16" once maxed.
- Extra monsters (Spawner/Refugee Camp) grant a decaying XP share instead of a flat 1 XP their old 0-XP flag couldn't actually reach.
- Used POI symbols now fully hide instead of just dimming.
## Version 1.9.5 — Economy & Marketplace Rework
### 🏪 Gold Becomes the Base Currency
- Wood and Stone are now bought/sold **against Gold**; no more direct Wood↔Stone route. Value anchor: 10 Gold ≡ 5 Wood ≡ 1 Stone.
- Price = base value × drift, spread on top. Each resource tracks a signed drift counter (buy +1/unit, sell −1/unit, clamped ±50%, recovers 10%/round).
- New batch-trading panel replaces the two-step wizard: quantity presets (1/5/25/100), one click = one full batch at one price.
- Merchant Guild now gives −10% markup (was +1 adjacency gold); Library gives −5% markup and stacks.
- Stone base value halved (5, was 10) and Quarry trimmed — stone was priced against a production rate implying ~3, making Quarry a better gold engine than the market itself. Buy/sell hover now shows live unit price.
### 📐 Recipe-Cluster Income Made Baseline
- The +3G/cluster recipe income was gated behind a Story-mode meta track and always returned 0 in Ranked. Now baseline in every mode; the Story track adds a further +2 on top instead of the full +3.
