Review todo: cloud Low lists (store, AI, MCP, device plane, DB/ops) - #472
Conversation
Ships the five "Cloud — …" Low sections of docs/review-todo.md in one PR. Scene store, images, render - Per-owner render concurrency (1 in flight, 2 waiting per account/client key) on top of the global 2-slot/8-deep queue; 429 render_concurrency_limit. - POST /api/scenes/render and the lint route run the same Origin/CSRF gate as the other mutating cookie routes (API-token bearers unchanged). - unzipBounded: streaming inflate that bounds the bytes actually produced, replacing every unzipSync call site; the declared-size check stays as the cheap pre-check. - Transparency verdict cached by content hash, not byte length. - Store scene delete is a typed-name dialog that points at yanking. - Yank re-projects description/tags/category from the version now served. The AI - get_frame wraps device-written last_state/last_metrics as untrusted. - Deleting or evicting a chat stops its running turn cleanly; appends after the row is gone return false instead of an FK error. - Chats get a title from the first user message; message_count follows the retained window after trimming. - The turn handle is passed into run() rather than closed over before init. - Relay maxDuration = the 15-min turn ceiling; both clients resume on a 16-min budget with backoff and a consecutive-unreachable cap. MCP server - Hints for invalid_frame, scene_pulled, insufficient_scope, the AI 402 and friends; too_many_scenes distinguishes the convert cap from the frame cap. - Nim→JS: `- -x` emits `-(-x)`; a shadowing `let` gets a fresh name. - repository.json cache is forgotten after every scene-changing tool and re-read once on a miss. - frame_logs filters (limit/search/since) server-side. - The anonymous convert route no longer distinguishes invalid_openai_key. Device plane - Replayed enrollment answers the link's current scopes. - First enrollment is race-safe (on conflict do nothing + re-register). - Log broadcast uses the rows that survived the cull. - Read-only tokens never enqueue device commands from GETs (403 read_only_token). - /asset answers 503 frame_offline immediately for offline/sleeping frames. - One normalizeAssetPath (control chars, backslashes) on both paths. - Backup quota checked and spent under a per-account advisory lock. - /command set_current_scene translates store uuids like the event route. Database, ops, deployment - grant-superadmin.sh matches account id or a verified identity email only. - Job tokens are minted with a TTL; the nightly route reports expiry. - db-cleanup.sh prunes password-reset and email-verification tokens. - 0053: indexes on every ON DELETE FK column that lacked one; schema.ts now declares every SQL-only index/unique constraint, guarded by a test that diffs drizzle/*.sql against the schema. - frameos-cloud-update --rollback is a stack (/opt/frameos-cloud.history). - Restore drill asserts on frame tables; frame-hub unit orders after postgres. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Sd9p5eSSzqxRqUj6GwCWEo
ESP32 firmware sizeBuilt from 906a713 by this run; compared with the latest release v2026.9.12.
Breakdown by subsystem —
|
| Subsystem | This PR | v2026.9.12 | Δ |
|---|---|---|---|
| FrameOS core (Nim) | 404,596 | 404,507 | +89 (+0.0%) |
| QuickJS | 356,332 | 356,332 | ±0 |
| FrameOS apps (Nim) | 318,368 | 317,959 | +409 (+0.1%) |
| pixie | 301,065 | 301,065 | ±0 |
| Wi-Fi stack | 295,300 | 295,304 | -4 (-0.0%) |
| Nim stdlib | 248,937 | 248,937 | ±0 |
| ESP-IDF misc | 178,065 | 178,057 | +8 (+0.0%) |
| Embedded font | 146,358 | 146,358 | ±0 |
| String pool (attributed to efuse) | 132,705 | 132,605 | +100 (+0.1%) |
| mbedTLS + certificates | 132,539 | 132,539 | ±0 |
| lwIP / HTTP / WebSocket | 126,640 | 126,640 | ±0 |
| fos_* firmware shell (C) | 116,897 | 116,298 | +599 (+0.5%) |
| libc / libm / newlib | 116,259 | 116,259 | ±0 |
| Storage (SPIFFS / FatFS / SD / NVS) | 94,136 | 94,136 | ±0 |
| Nim packages (chrono, zippy, chroma, qrgen, ...) | 72,031 | 72,031 | ±0 |
| Display drivers (C) | 64,690 | 64,690 | ±0 |
| Crypto (monocypher) | 35,149 | 35,149 | ±0 |
| Total mapped flash | 3,140,067 | 3,138,866 | +1,201 (+0.0%) |
Inside each subsystem
FrameOS core (Nim) — 404,596
| Part | This PR | v2026.9.12 | Δ |
|---|---|---|---|
frameos/js_runtime |
102,117 | 102,114 | +3 (+0.0%) |
frameos/interpreter.nim |
97,344 | 97,352 | -8 (-0.0%) |
frameos/utils |
89,644 | 89,574 | +70 (+0.1%) |
embedded_main.nim |
18,351 | 18,351 | ±0 |
lib/tz.nim |
16,875 | 16,875 | ±0 |
embedded_runtime.nim |
15,056 | 15,056 | ±0 |
frameos_nim_glue.c.obj |
9,814 | 9,814 | ±0 |
frameos/planner.nim |
9,605 | 9,605 | ±0 |
frameos/types.nim |
7,913 | 7,893 | +20 (+0.3%) |
frameos/values.nim |
6,901 | 6,901 | ±0 |
frameos/apps.nim |
6,046 | 6,046 | ±0 |
frameos/spool.nim |
5,678 | 5,678 | ±0 |
embedded_scene.nim |
4,945 | 4,945 | ±0 |
frameos/app_config.nim |
2,871 | 2,871 | ±0 |
frameos/reboot_reason.nim |
2,628 | 2,628 | ±0 |
frameos/node_config.nim |
2,590 | 2,590 | ±0 |
frameos/app_capabilities.nim |
2,493 | 2,493 | ±0 |
fos_netguard.c.obj |
2,092 | 2,088 | +4 (+0.2%) |
frameos/runtime_diagnostics.nim |
763 | 763 | ±0 |
fos_version.c.obj |
324 | 324 | ±0 |
frameos/cloud |
255 | 255 | ±0 |
frameos/ids.nim |
133 | 133 | ±0 |
frameos/channels.nim |
118 | 118 | ±0 |
frameos/hal |
40 | 40 | ±0 |
QuickJS — 356,332
| Part | This PR | v2026.9.12 | Δ |
|---|---|---|---|
quickjs.c.obj |
283,817 | 283,817 | ±0 |
libunicode.c.obj |
50,174 | 50,174 | ±0 |
libregexp.c.obj |
13,995 | 13,995 | ±0 |
dtoa.c.obj |
5,681 | 5,681 | ±0 |
cutils.c.obj |
2,141 | 2,141 | ±0 |
fos_qjs_glue.c.obj |
449 | 449 | ±0 |
fos_quickjs_tz.c.obj |
75 | 75 | ±0 |
FrameOS apps (Nim) — 318,368
| Part | This PR | v2026.9.12 | Δ |
|---|---|---|---|
apps/data/icalJson |
50,265 | 50,265 | ±0 |
apps/render/calendar |
30,666 | 30,666 | ±0 |
apps/render/chart |
21,541 | 21,541 | ±0 |
apps/data/immich |
17,542 | 17,538 | +4 (+0.0%) |
apps/data/wikicommons |
17,110 | 17,110 | ±0 |
apps/data/openaiImage |
13,926 | 13,926 | ±0 |
apps/data/beRecycle |
11,166 | 10,749 | +417 (+3.9%) |
apps/data/unsplash |
11,056 | 11,056 | ±0 |
apps/data/weather |
10,210 | 10,210 | ±0 |
apps/render/split |
9,648 | 9,648 | ±0 |
apps/data/localImage |
9,186 | 9,190 | -4 (-0.0%) |
apps/data/eventsToAgenda |
9,084 | 9,084 | ±0 |
apps/data/googlePhotos |
9,068 | 9,068 | ±0 |
apps/apps.nim |
8,636 | 8,636 | ±0 |
apps/render/zoomPan |
8,552 | 8,552 | ±0 |
apps/data/openaiText |
7,353 | 7,353 | ±0 |
apps/data/haSensor |
7,291 | 7,291 | ±0 |
apps/render/text |
5,423 | 5,423 | ±0 |
apps/data/xmlToJson |
5,420 | 5,420 | ±0 |
apps/render/svg |
5,176 | 5,176 | ±0 |
apps/render/image |
4,510 | 4,510 | ±0 |
apps/data/rotateImage |
3,457 | 3,457 | ±0 |
apps/logic/setAsState |
3,441 | 3,441 | ±0 |
apps/data/downloadImage |
3,333 | 3,333 | ±0 |
apps/render/gradient |
3,173 | 3,173 | ±0 |
apps/data/qr |
3,118 | 3,118 | ±0 |
apps/data/downloadUrl |
3,065 | 3,065 | ±0 |
apps/data/frameOSGallery |
3,006 | 3,006 | ±0 |
apps/render/color |
2,804 | 2,804 | ±0 |
apps/data/newImage |
2,652 | 2,652 | ±0 |
apps/data/resizeImage |
2,550 | 2,550 | ±0 |
apps/data/log |
2,283 | 2,283 | ±0 |
apps/render/opacity |
2,272 | 2,272 | ±0 |
apps/data/prettyJson |
2,213 | 2,213 | ±0 |
apps/data/parseJson |
1,844 | 1,844 | ±0 |
apps/data/clock |
1,835 | 1,843 | -8 (-0.4%) |
apps/logic/nextSleepDuration |
1,639 | 1,639 | ±0 |
apps/logic/ifElse |
1,476 | 1,476 | ±0 |
apps/logic/breakIfRendering |
1,378 | 1,378 | ±0 |
pixie — 301,065
| Part | This PR | v2026.9.12 | Δ |
|---|---|---|---|
pixie/fontformats/opentype.nim |
55,507 | 55,507 | ±0 |
pixie/fileformats/webp.nim |
37,525 | 37,525 | ±0 |
pixie/fileformats/svg.nim |
37,203 | 37,203 | ±0 |
pixie/paths.nim |
32,570 | 32,570 | ±0 |
pixie/fileformats/jpeg.nim |
25,338 | 25,338 | ±0 |
pixie/fileformats/png.nim |
22,849 | 22,849 | ±0 |
pixie/images.nim |
15,787 | 15,787 | ±0 |
pixie/fonts.nim |
11,019 | 11,019 | ±0 |
pixie/paints.nim |
9,889 | 9,889 | ±0 |
pixie/fileformats/bmp.nim |
8,234 | 8,234 | ±0 |
pixie/common.nim |
7,416 | 7,416 | ±0 |
pixie/blends.nim |
6,540 | 6,540 | ±0 |
pixie/fileformats/gif.nim |
5,929 | 5,929 | ±0 |
pixie/inflatestream.nim |
5,325 | 5,325 | ±0 |
pixie.nim |
5,248 | 5,248 | ±0 |
pixie/fileformats/webp_vp8_tables.nim |
3,881 | 3,881 | ±0 |
pixie/fileformats/ppm.nim |
3,681 | 3,681 | ±0 |
pixie/contexts.nim |
3,038 | 3,038 | ±0 |
pixie/fileformats/qoi.nim |
2,686 | 2,686 | ±0 |
pixie/internal.nim |
754 | 754 | ±0 |
pixie/rgb565.nim |
381 | 381 | ±0 |
pixie/fontformats/svgfont.nim |
215 | 215 | ±0 |
pixie/decodebudget.nim |
50 | 50 | ±0 |
Wi-Fi stack — 295,300
| Part | This PR | v2026.9.12 | Δ |
|---|---|---|---|
libnet80211.a |
136,168 | 136,168 | ±0 |
libpp.a |
62,154 | 62,154 | ±0 |
libwpa_supplicant.a |
54,900 | 54,900 | ±0 |
libphy.a |
34,176 | 34,176 | ±0 |
libesp_wifi.a |
4,780 | 4,784 | -4 (-0.1%) |
libesp_phy.a |
2,541 | 2,541 | ±0 |
libesp_coex.a |
291 | 291 | ±0 |
libcore.a |
287 | 287 | ±0 |
libespnow.a |
3 | 3 | ±0 |
Nim stdlib — 248,937
| Part | This PR | v2026.9.12 | Δ |
|---|---|---|---|
pure/collections/tables.nim |
70,556 | 70,556 | ±0 |
system.nim |
46,665 | 46,665 | ±0 |
pure/unicode.nim |
17,405 | 17,405 | ±0 |
pure/times.nim |
16,984 | 16,984 | ±0 |
pure/json.nim |
13,414 | 13,414 | ±0 |
std/private/dragonbox.nim |
10,351 | 10,351 | ±0 |
pure/strutils.nim |
8,473 | 8,473 | ±0 |
pure/parsexml.nim |
5,975 | 5,975 | ±0 |
pure/algorithm.nim |
5,368 | 5,368 | ±0 |
pure/base64.nim |
5,302 | 5,302 | ±0 |
pure/hashes.nim |
4,114 | 4,114 | ±0 |
pure/xmlparser.nim |
3,567 | 3,567 | ±0 |
pure/parsejson.nim |
3,553 | 3,553 | ±0 |
std/formatfloat.nim |
3,508 | 3,508 | ±0 |
pure/uri.nim |
3,225 | 3,225 | ±0 |
pure/collections/sets.nim |
3,211 | 3,211 | ±0 |
pure/streams.nim |
2,820 | 2,820 | ±0 |
pure/strformat.nim |
2,641 | 2,641 | ±0 |
std/syncio.nim |
2,355 | 2,355 | ±0 |
pure/xmltree.nim |
2,051 | 2,051 | ±0 |
pure/lexbase.nim |
1,805 | 1,805 | ±0 |
pure/parseutils.nim |
1,757 | 1,757 | ±0 |
system/exceptions.nim |
1,598 | 1,598 | ±0 |
pure/strtabs.nim |
1,568 | 1,568 | ±0 |
pure/pathnorm.nim |
1,332 | 1,332 | ±0 |
pure/options.nim |
1,118 | 1,118 | ±0 |
std/private/ospaths2.nim |
1,032 | 1,032 | ±0 |
pure/collections/lists.nim |
983 | 983 | ±0 |
system/dollars.nim |
891 | 891 | ±0 |
pure/random.nim |
835 | 835 | ±0 |
std/private/digitsutils.nim |
651 | 651 | ±0 |
pure/math.nim |
650 | 650 | ±0 |
std/oserrors.nim |
637 | 637 | ±0 |
std/private/osdirs.nim |
580 | 580 | ±0 |
std/monotimes.nim |
401 | 401 | ±0 |
std/private/oscommon.nim |
329 | 329 | ±0 |
std/envvars.nim |
250 | 250 | ±0 |
std/private/decode_helpers.nim |
240 | 240 | ±0 |
std/private/ossymlinks.nim |
187 | 187 | ±0 |
pure/bitops.nim |
162 | 162 | ±0 |
pure/os.nim |
99 | 99 | ±0 |
std/private/osfiles.nim |
96 | 96 | ±0 |
std/assertions.nim |
87 | 87 | ±0 |
core/macros.nim |
69 | 69 | ±0 |
system/iterators.nim |
33 | 33 | ±0 |
system/ctypes.nim |
9 | 9 | ±0 |
ESP-IDF misc — 178,065
| Part | This PR | v2026.9.12 | Δ |
|---|---|---|---|
libesp_hw_support.a |
37,650 | 37,650 | ±0 |
libhal.a |
21,464 | 21,464 | ±0 |
libfreertos.a |
17,194 | 17,194 | ±0 |
libesp_system.a |
13,780 | 13,780 | ±0 |
libesp_driver_uart.a |
11,627 | 11,627 | ±0 |
libheap.a |
8,660 | 8,656 | +4 (+0.0%) |
libesp_driver_i2c.a |
8,062 | 8,062 | ±0 |
libesp_driver_spi.a |
7,756 | 7,756 | ±0 |
libconsole.a |
5,733 | 5,733 | ±0 |
libjson.a |
4,940 | 4,940 | ±0 |
libesp_driver_gpio.a |
3,890 | 3,890 | ±0 |
libbootloader_support.a |
3,813 | 3,813 | ±0 |
libxtensa.a |
3,691 | 3,691 | ±0 |
libesp_driver_usb_serial_jtag.a |
3,408 | 3,408 | ±0 |
libesp_ringbuf.a |
3,322 | 3,322 | ±0 |
libesp_event.a |
3,257 | 3,253 | +4 (+0.1%) |
libesp_mm.a |
2,451 | 2,451 | ±0 |
libapp_update.a |
2,422 | 2,422 | ±0 |
libesp_psram.a |
2,329 | 2,329 | ±0 |
libesp_timer.a |
2,326 | 2,326 | ±0 |
libsoc.a |
2,315 | 2,315 | ±0 |
libesp_adc.a |
2,289 | 2,289 | ±0 |
liblog.a |
1,375 | 1,375 | ±0 |
libpthread.a |
1,365 | 1,365 | ±0 |
libesp_security.a |
1,050 | 1,050 | ±0 |
libesp_rom.a |
902 | 902 | ±0 |
libesp_app_format.a |
507 | 507 | ±0 |
libxt_hal.a |
437 | 437 | ±0 |
libesp_common.a |
26 | 26 | ±0 |
libesp_pm.a |
24 | 24 | ±0 |
Embedded font — 146,358
| Part | This PR | v2026.9.12 | Δ |
|---|---|---|---|
assets/fonts.nim |
146,358 | 146,358 | ±0 |
String pool (attributed to efuse) — 132,705
| Part | This PR | v2026.9.12 | Δ |
|---|---|---|---|
esp_efuse_utility.c.obj |
131,659 | 131,559 | +100 (+0.1%) |
esp_efuse_rtc_calib.c.obj |
566 | 566 | ±0 |
esp_efuse_table.c.obj |
268 | 268 | ±0 |
esp_efuse_api.c.obj |
151 | 151 | ±0 |
esp_efuse_startup.c.obj |
61 | 61 | ±0 |
mbedTLS + certificates — 132,539
| Part | This PR | v2026.9.12 | Δ |
|---|---|---|---|
libmbedcrypto.a |
71,391 | 71,391 | ±0 |
libmbedtls.a |
45,803 | 45,803 | ±0 |
libmbedx509.a |
7,084 | 7,084 | ±0 |
libesp-tls.a |
6,709 | 6,709 | ±0 |
libesp_https_server.a |
1,552 | 1,552 | ±0 |
lwIP / HTTP / WebSocket — 126,640
| Part | This PR | v2026.9.12 | Δ |
|---|---|---|---|
liblwip.a |
78,301 | 78,301 | ±0 |
libhttp_parser.a |
10,350 | 10,350 | ±0 |
libesp_http_server.a |
10,016 | 10,016 | ±0 |
libtcp_transport.a |
8,237 | 8,237 | ±0 |
libespressif__esp_websocket_client.a |
6,826 | 6,826 | ±0 |
libesp_http_client.a |
6,666 | 6,666 | ±0 |
libesp_netif.a |
6,244 | 6,244 | ±0 |
fos_ firmware shell (C)* — 116,897
| Part | This PR | v2026.9.12 | Δ |
|---|---|---|---|
fos_http.c.obj |
22,202 | 22,034 | +168 (+0.8%) |
fos_cloud.c.obj |
16,975 | 17,935 | -960 (-5.4%) |
fos_console.c.obj |
13,601 | 13,501 | +100 (+0.7%) |
fos_client.c.obj |
10,499 | 10,483 | +16 (+0.2%) |
fos_scenes.c.obj |
7,551 | 7,551 | ±0 |
fos_settings.c.obj |
6,511 | 6,511 | ±0 |
fos_ota.c.obj |
5,039 | 5,775 | -736 (-12.7%) |
fos_config.c.obj |
4,298 | 5,755 | -1,457 (-25.3%) |
fos_assets.c.obj |
3,124 | 3,282 | -158 (-4.8%) |
fos_wifi.c.obj |
3,201 | 3,201 | ±0 |
fos_cloud_contract.c.obj |
2,896 | 2,896 | ±0 |
fos_sd_probe.c.obj |
2,753 | 2,753 | ±0 |
fos_assets_sd.c.obj |
2,480 | 2,480 | ±0 |
fos_schedule.c.obj |
2,351 | 2,339 | +12 (+0.5%) |
fos_buttons.c.obj |
2,139 | 2,139 | ±0 |
fos_status_screen.c.obj |
2,049 | 2,049 | ±0 |
main.c.obj |
1,667 | 1,673 | -6 (-0.4%) |
fos_config_parse.c.obj |
1,467 | — | +1,467 |
fos_url_guard.c.obj |
1,397 | — | +1,397 |
fos_tz.c.obj |
1,381 | 1,381 | ±0 |
fos_battery.c.obj |
1,140 | 1,140 | ±0 |
fos_minisig.c.obj |
497 | — | +497 |
fos_framebuffer.c.obj |
483 | 483 | ±0 |
fos_assets_path.c.obj |
259 | — | +259 |
fos_power.c.obj |
241 | 241 | ±0 |
fos_battery_filter.c.obj |
214 | 214 | ±0 |
fos_wake.c.obj |
184 | 184 | ±0 |
fos_board.c.obj |
179 | 179 | ±0 |
fos_json_guard.c.obj |
119 | 119 | ±0 |
libc / libm / newlib — 116,259
| Part | This PR | v2026.9.12 | Δ |
|---|---|---|---|
libc.a |
76,467 | 76,467 | ±0 |
libm.a |
31,563 | 31,563 | ±0 |
libnewlib.a |
6,609 | 6,609 | ±0 |
libstdc++.a |
1,476 | 1,476 | ±0 |
libgcc.a |
98 | 98 | ±0 |
libcxx.a |
46 | 46 | ±0 |
Storage (SPIFFS / FatFS / SD / NVS) — 94,136
| Part | This PR | v2026.9.12 | Δ |
|---|---|---|---|
libspiffs.a |
20,380 | 20,380 | ±0 |
libfatfs.a |
20,133 | 20,133 | ±0 |
libspi_flash.a |
14,168 | 14,168 | ±0 |
libnvs_flash.a |
13,745 | 13,745 | ±0 |
libsdmmc.a |
13,013 | 13,013 | ±0 |
libvfs.a |
6,196 | 6,196 | ±0 |
libesp_driver_sdspi.a |
3,858 | 3,858 | ±0 |
libesp_partition.a |
1,960 | 1,960 | ±0 |
libesp_vfs_console.a |
678 | 678 | ±0 |
libnvs_sec_provider.a |
5 | 5 | ±0 |
Nim packages (chrono, zippy, chroma, qrgen, ...) — 72,031
| Part | This PR | v2026.9.12 | Δ |
|---|---|---|---|
QRgen 3.1.0 |
22,036 | 22,036 | ±0 |
chrono 0.3.1 |
15,514 | 15,514 | ±0 |
zippy 0.10.19 |
15,272 | 15,272 | ±0 |
chroma 1.0.0 |
14,916 | 14,916 | ±0 |
checksums 0.2.1 |
3,371 | 3,371 | ±0 |
flatty 0.3.4 |
533 | 533 | ±0 |
jsony 1.1.5 |
272 | 272 | ±0 |
bumpy 1.1.3 |
117 | 117 | ±0 |
Display drivers (C) — 64,690
| Part | This PR | v2026.9.12 | Δ |
|---|---|---|---|
(everything else) |
21,249 | 21,249 | ±0 |
frameos_panel_table.c.obj |
6,685 | 6,685 | ±0 |
EPD_13in3e.c.obj |
1,792 | 1,792 | ±0 |
EPD_3in7.c.obj |
1,556 | 1,556 | ±0 |
EPD_5in79.c.obj |
1,478 | 1,478 | ±0 |
EPD_2in7.c.obj |
1,289 | 1,289 | ±0 |
EPD_4in2.c.obj |
1,255 | 1,255 | ±0 |
EPD_7in3e.c.obj |
1,208 | 1,208 | ±0 |
DEV_Debug.c.obj |
1,206 | 1,206 | ±0 |
EPD_4in2_V2.c.obj |
1,184 | 1,184 | ±0 |
DEV_Config_esp.c.obj |
1,180 | 1,180 | ±0 |
EPD_4in26.c.obj |
1,123 | 1,123 | ±0 |
| 29 smaller rows | 23,485 | 23,485 | ±0 |
Crypto (monocypher) — 35,149
| Part | This PR | v2026.9.12 | Δ |
|---|---|---|---|
monocypher.c.obj |
31,920 | 31,920 | ±0 |
monocypher-ed25519.c.obj |
3,229 | 3,229 | ±0 |
Biggest movers (per object)
| Object | Δ | This PR | Baseline |
|---|---|---|---|
fos_config.c.obj |
-1,457 | 4,298 | 5,755 |
fos_cloud.c.obj |
-960 | 16,975 | 17,935 |
fos_ota.c.obj |
-736 | 5,039 | 5,775 |
apps/data/beRecycle/app.nim |
+417 | 9,680 | 9,263 |
fos_http.c.obj |
+168 | 22,202 | 22,034 |
fos_console.c.obj |
+100 | 13,601 | 13,501 |
esp_efuse_utility.c.obj |
+100 | 131,659 | 131,559 |
frameos/utils/status_screen.nim |
+24 | 17,947 | 17,923 |
frameos/types.nim |
+20 | 7,913 | 7,893 |
frameos/utils/font.nim |
+16 | 5,583 | 5,567 |
fos_client.c.obj |
+16 | 10,499 | 10,483 |
frameos/utils/image.nim |
-12 | 34,362 | 34,374 |
frameos/interpreter.nim |
-8 | 97,344 | 97,352 |
tlsf.c.obj |
+4 | 4,284 | 4,280 |
apps/data/immich/app.nim |
+4 | 15,995 | 15,991 |
Largest 30 objects
| Object | Subsystem | This PR | v2026.9.12 | Δ |
|---|---|---|---|---|
quickjs.c.obj |
QuickJS | 283,817 | 283,817 | ±0 |
assets/fonts.nim |
Embedded font | 146,358 | 146,358 | ±0 |
esp_efuse_utility.c.obj |
String pool (attributed to efuse) | 131,659 | 131,559 | +100 (+0.1%) |
frameos/interpreter.nim |
FrameOS core (Nim) | 97,344 | 97,352 | -8 (-0.0%) |
nim/lib/pure/collections/tables.nim |
Nim stdlib | 70,556 | 70,556 | ±0 |
frameos/js_runtime/app_runtime.nim |
FrameOS core (Nim) | 61,505 | 61,502 | +3 (+0.0%) |
pkgs/pixie-6.1.0/pixie/fontformats/opentype.nim |
pixie | 55,507 | 55,507 | ±0 |
libunicode.c.obj |
QuickJS | 50,174 | 50,174 | ±0 |
nim/lib/system.nim |
Nim stdlib | 46,665 | 46,665 | ±0 |
apps/data/icalJson/ical.nim |
FrameOS apps (Nim) | 44,568 | 44,568 | ±0 |
pkgs/pixie-6.1.0/pixie/fileformats/webp.nim |
pixie | 37,525 | 37,525 | ±0 |
pkgs/pixie-6.1.0/pixie/fileformats/svg.nim |
pixie | 37,203 | 37,203 | ±0 |
frameos/utils/image.nim |
FrameOS core (Nim) | 34,362 | 34,374 | -12 (-0.0%) |
pkgs/pixie-6.1.0/pixie/paths.nim |
pixie | 32,570 | 32,570 | ±0 |
monocypher.c.obj |
Crypto (monocypher) | 31,920 | 31,920 | ±0 |
frameos/js_runtime/runtime.nim |
FrameOS core (Nim) | 30,094 | 30,094 | ±0 |
pkgs/pixie-6.1.0/pixie/fileformats/jpeg.nim |
pixie | 25,338 | 25,338 | ±0 |
apps/render/calendar/app.nim |
FrameOS apps (Nim) | 23,618 | 23,618 | ±0 |
pkgs/pixie-6.1.0/pixie/fileformats/png.nim |
pixie | 22,849 | 22,849 | ±0 |
fos_http.c.obj |
fos_* firmware shell (C) | 22,202 | 22,034 | +168 (+0.8%) |
apps/render/chart/app.nim |
FrameOS apps (Nim) | 18,940 | 18,940 | ±0 |
embedded_main.nim |
FrameOS core (Nim) | 18,351 | 18,351 | ±0 |
frameos/utils/status_screen.nim |
FrameOS core (Nim) | 17,947 | 17,923 | +24 (+0.1%) |
x509_crt_bundle.S.obj |
mbedTLS + certificates | 17,928 | 17,928 | ±0 |
nim/lib/pure/unicode.nim |
Nim stdlib | 17,405 | 17,405 | ±0 |
nim/lib/pure/times.nim |
Nim stdlib | 16,984 | 16,984 | ±0 |
fos_cloud.c.obj |
fos_* firmware shell (C) | 16,975 | 17,935 | -960 (-5.4%) |
lib/tz.nim |
FrameOS core (Nim) | 16,875 | 16,875 | ±0 |
apps/data/immich/app.nim |
FrameOS apps (Nim) | 15,995 | 15,991 | +4 (+0.0%) |
pkgs/pixie-6.1.0/pixie/images.nim |
pixie | 15,787 | 15,787 | ±0 |
Flash = .text + .rodata from the linker map via esp_idf_size; "Inside each subsystem" splits every bucket one level down (the Nim core by directory, apps by app, packages by package, ESP-IDF by archive) over all objects, not just the largest. "String pool (attributed to efuse)" is the linker's merged string-literal pool for the whole image, not efuse code — see docs/esp32-image-size.md.
Ships the five "Cloud — …" Low sections of
docs/review-todo.md(scene store/images/render, the AI, MCP server, device plane, database/ops/deployment) — 32 items in one PR, five fork agents in one shared worktree.Scene store, images, render
429 render_concurrency_limit,retry-afteron 429/503.POST /api/scenes/renderand the lint route run the same Origin/CSRF gate as the other mutating cookie routes; API-token bearers unchanged.unzipBounded(src/lib/zip-bounded.ts): parses the central directory itself and inflates selected entries through fflate's streamingInflatein 8 KB slices, checking the actual inflated total. Replaces all 8unzipSynccall sites. Test proves a 4 MB stream with a 100-byte header is refused under a 1 MB ceiling (fflate's sync path silently truncated it before).window.confirm.The AI
get_framereturnslast_state/last_metricsinside theuntrusted_dataframe.appendChatMessagereturnsfalseon a missing chat row instead of surfacing the FK error.message_countfollows the retained window after trimming.startTurn'srunreceives the registered turn instead of closing over theconstbefore it is initialised.maxDuration = 900(= the turn ceiling); both chat clients resume on a 16-min budget with backoff and a 30-consecutive-unreachable cap.MCP server
invalid_frame,scene_pulled,insufficient_scope,daily_cap_reached(402),ai_disabled,invalid_openai_key,model_budget_exhausted,model_failed;too_many_scenesdistinguishes the convert cap from the frame's 20-scene cap.- -x→-(-x); aletshadowing an argument or earlier binding gets a fresh name instead of a TDZ read.repository.jsoncache forgotten after every scene-changing tool; one fresh re-read on a miss.frame_logssendslimit/search/since;GET /api/frames/{id}/logsapplies them (ILIKE with wildcard escaping, bounded).502 model_failedfor a bad caller-supplied key; only signed-in callers seeinvalid_openai_key.Device plane
on conflict do nothingonlinked_client_id, the loser re-registers against the winner (three concurrent enrollments → one frame, all 200).RETURNING+ in-transaction survivor select)./asset,/image,/assets,/scene_images/{scene}) →403 read_only_tokenwhen only the device could answer./assetanswers503 frame_offline+Retry-After: 60immediately for disconnected or sleeping frames (still queues the fetch).normalizeAssetPath(control chars,.., backslashes) on both paths./command set_current_sceneruns the scene id throughdeviceSceneIdForFramelike the event route.Database, ops, deployment
grant-superadmin.shtakes an account id or a verified identity email; unverified-only matches are refused.POST /api/admin/billing/nightlyreportstoken_expires_at, the nightly script warns for the last 14 days. Runbook updated.db-cleanup.shprunes expired/usedpassword_reset_tokensandemail_verification_tokens; integration test runs the real script.0053_fk_delete_indexes.sql: 11 indexes on ON DELETE FK columns that lacked one.schema.tsnow declares every SQL-only index and three UNIQUE constraints it mis-declared as unique indexes;schema-migrations.test.tsdiffsdrizzle/*.sqlagainst the schema both ways.frameos-cloud-update --rollbackis a stack (/opt/frameos-cloud.history); rehearsal step 6 extended and passing in Docker.deployment.mdgetsRequires=/After=postgresql.service.Verification
ai-save-scene(a globalstore_imagescount) is now a before/after delta.🤖 Generated with Claude Code
https://claude.ai/code/session_01Sd9p5eSSzqxRqUj6GwCWEo