# Symbol Check — BibleVerse session (updated July 12 v5 pretty font)

## Tool: undefined symbols vs firmware exports

```python
import pathlib, re, subprocess
elf = pathlib.Path("Apps/BibleVerse/build/cmake-build-esp32s3/BibleVerse.app.elf")
r = subprocess.run(["zsh","-c", f"source ~/esp/esp-idf/export.sh >/dev/null 2>&1; xtensa-esp32s3-elf-nm -D {elf}"], capture_output=True, text=True)
undef = [l.split()[-1] for l in r.stdout.splitlines() if len(l.split())>=2 and l.split()[-2]=='U']

pat = re.compile(r'(?:ESP_ELFSYM_EXPORT|DEFINE_MODULE_SYMBOL)\s*\(\s*([A-Za-z0-9_]+)\s*\)')
exp=set()
for fp in pathlib.Path("../firmware").rglob("*.*"):
  if 'build' in str(fp): continue
  if fp.suffix not in ('.c','.h','.cpp'): continue
  try: exp.update(m.group(1) for m in pat.finditer(fp.read_text(errors='ignore')))
  except: pass
missing = [s for s in undef if s not in exp]
print(f"undef {len(undef)} missing {missing}")
```

## Session results

- Before fix: `undef 68, missing ['lv_font_montserrat_14']` — source used `&lv_font_montserrat_14`.
- After `lvgl_get_text_font(FONT_SIZE_SMALL)`: `undef 68, missing []` ✅
- Editorial v4: 0 missing, anim symbols ok, app 4413440 bytes, heap 54KB stable on .129
- **v5 pretty font**: Georgia Italic embedded C 26/22/20/18/16 + regular 24 via `lv_font_conv`, 315KB `.rodata` in PSRAM, 0 missing, app 4.3MB, heap `47539 free largest 20480 psram 4810944` stable, screenshot 5336 bytes Habakkuk 1:17 serif italic editorial.
- **v6 final beautiful 2142871**: 0 missing, `undef 0`, app 4.3M, heap `46215-47591 free largest 20480 psram 4810396` stable, screenshots 8683 menu visible (top Zeph 1:3 / 31094 + bottom pills) + 6882 immersive hidden, lift -7 15px corrected from -22 30px per user, black bar fixed. Gotcha `lv_timer_t user_data` field incomplete → `t->user_data` invalid → must use `lv_timer_get_user_data(t)` + `lv_timer_set_user_data` (exports 372/373/382/388). Checked `grep timer symbols.c`. Timer used for chrome auto-hide 10s + book browser anim.

## Known missing table

| Symbol | Status | Workaround |
|---|---|---|
| `lv_font_montserrat_14/18/24` | Not exported | `lvgl_get_text_font(FONT_SIZE_SMALL/DEFAULT/LARGE)` OR embedded C serif via `lv_font_conv` → see `pretty-font.md` |
| `LV_SYMBOL_STAR` | May be absent | Use `LV_SYMBOL_OK`, `LV_SYMBOL_DUMMY` |
| `xTaskGetCurrentTaskHandle` | Not exported | Avoid task identity check; release lock |
| `lv_image_set_rotation` | Not exported | `lv_obj_set_style_transform_rotation(obj, deg*10, 0)` |
| `cJSON`, `esp_websocket_client` | Static | Vendor source or raw `lwip_socket` APIs |

### New missing from v2/v3/v4/v5 UI passes

- `lv_obj_set_style_bg_grad_color/dir/stop` → **Not exported** 0.8.0-dev. Gradient fails `missing symbol`. Use solid `0x0E0E14`.
- `LV_OPA_95` → **Not defined** (only 0/10/20/30/40/50/60/70/80/90/100/COVER/TRANSP). Use `COVER` or `90`.
- `lv_arc_create`, `lv_arc_set_range/value/bg_angles`, `lv_arc_get_value` → **Not exported on 0.7.0-dev**, added `dff93cb6 Add lv_arc.h symbols (#496)` after 0.7 release. Symptom blue modal `Error / Application failed to start: missing symbol / OK`, heap healthy ~31KB not OOM. Fix horizontal slide using `lv_slider_create` + `lv_indev_get_point/active`. See `book-browser.md`.
- `lv_roller_create` → **Not exported** 0.7 nor 0.8.
- `lv_indev_get_point/active`, `lv_slider_create/range/value/set_value` → **Exported since 0.6** safe.
- `lv_anim_init`, `set_var/values/duration/exec_cb/path_cb/start`, `path_ease_out/linear/ease_in`, `path_ease_in_out` → **Exported since 0.6** safe (checked lines 435-446). Used for editorial fade 220/300ms. Safe for 0.7/0.8 fleet.
- `lv_binfont_create/destroy` → **Exported** 0.8 but VFS path fragile — `tt_app_get_assets_path` returns void, not bool (check `buf[0]!='\0'`). Prefer **embedded C** fonts via `LV_FONT_DECLARE` — lives in PSRAM (315KB `.rodata`), no FS needed. See `pretty-font.md`. Old `.fnt` bins 52KB still bundled in `assets/fonts/` but not used.
- `lv_font_t` embedded C — no symbol needed, static const.

## Heap OOM vs missing-symbol distinction

- **OOM**: `heap free 275B total 310KB largest_block 23`, install `500 failed to create temp directory`, screenshot `500`. Cause 66-button browser 132-264 objs. Fix ~10 obj browser.
- **Missing symbol**: `heap free 31779 largest 12288` healthy, install `200 ok`, run `200 ok`, but app shows blue `Error missing symbol` dialog, screenshot `200 2755`. Fix check `symbols.c`.

## Font scaling v4/v5

Only 3 sizes via `lvgl_get_text_font()` fallback, but v5 uses embedded serif as primary:

```c
size_t len = strlen(verse);
enum LvglFontSize fs; int line_sp, pad_v, pad_h;
if (len < 40)      { fs=FONT_SIZE_LARGE;   line_sp=14; pad_v=10; pad_h=28; letter_sp=1; } // v4 tightened
else if (len <100) { fs=FONT_SIZE_LARGE;   line_sp=10; pad_v=8; pad_h=24; }
else if (len <200) { fs=FONT_SIZE_DEFAULT; line_sp=8;  pad_v=6; pad_h=20; }
else if (len <350) { fs=FONT_SIZE_SMALL;   line_sp=6;  pad_v=4; pad_h=16; }
else               { fs=FONT_SIZE_SMALL;   line_sp=4;  pad_v=2; pad_h=12; } // Esther 492c

// v5: resolve to embedded Georgia Italic 26/20/16 else fallback
lv_obj_set_style_text_font(lbl_verse, resolve_verse_font(ctx, fs), 0);
```

Proven .112 Genesis 2:10 77c LARGE, .129 Ephesians 1:4 4138 bytes screenshot editorial warm `#F2F0E8` + ref uppercase tracking 2 `#9A9AA8` gap 10, v5 Habakkuk 1:17 5336 bytes serif italic editorial vision PASS.

Exported: `lvgl_get_text_font`, `get_text_font_height`, `get_shared_icon_font`, `set_style_text_font`, `timer_create`, `label_set_text`, `text_line_space`, `pad_*`, `text_opa`, `anim_*`, `LV_FONT_DECLARE` (macro, not symbol).

CI: fail if missing>0, heap stable >40KB with fonts.
