Skip to content

pico_w_test: serve the licence page from LittleFS, for 3,699 B of room under the OTA ceiling - #297

Merged
angeloINTJ merged 2 commits into
mainfrom
chore/test-image-license-fs
Oct 28, 2026
Merged

angeloINTJ merged 2 commits into
mainfrom
chore/test-image-license-fs

Conversation

@angeloINTJ

Copy link
Copy Markdown
Owner

What

pico_w_test, the bench image with the full CLI (not published), serves its licence page from LittleFS instead of carrying it in flash: LICENSE_PAGE joins its custom_fs_pages, as #288 did for pico_w_test_https. The second commit fixes a file name in the https profile's comment (telemetry.html.gz, not tel.html.gz).

Why

On main 9f4da77 pico_w_test signs at 1,040,309 B against the OTA ceiling of 1,040,384 B: 75 B of room (763 B at 2075b84; #294 and #295 took 688 B). The UI-drivers branch, after syncing with main, is 101 B over. The profile's own comment says to take room from this image, never from the release; the maintainer chose this cut on 2026-10-28.

Measured

All nine images built from scratch on 9f4da77 plus this change, check_flash_budget.py right after each build:

before after
pico_w_test flash used 1,028,036 B 1,024,412 B
pico_w_test .bin 1,040,068 B 1,036,444 B
signed 1,040,309 B 1,036,685 B
room under the OTA ceiling 75 B 3,699 B
  • The gain is 3,624 B, not the page's 4,260 B. Before this change the image served no page from a file, so the change also links serveProtectedFsPage( ) (+428 B) and the "Page asset missing" strings (+212 B). nm -S -C shows these, plus handleLicense( ) going from 24 B to 16 B; no other symbol changes size.
  • The other eight images (pico_w_release, pico_w_test_https, pico_w_asserts, pico_w_alpha, pico_w_air, pico2_w_release, pico_wire, pico_wiretft) are sha256-identical to main's; the commit message lists the hashes.
  • tools/flash_budget.json and the section 3.1 row of PLANO_STABLE.md record the new figures. --table, test_flash_budget.py (24 ok), gen_features.py --check, check_features.py, check_readme_numbers.py, check_angulo.py and the 41 Python commands of the CI gates job all pass.
  • The room is still under one 4 KiB sector, so the gate's WARN stays.

Bench impact

The deploy step grows, for both bench images. AGENTS.md (Gravar firmware) now says once for the two of them:

  • upload the .gz that the build leaves in data/web/ to /web/ with POST /api/upload?uploadDir=/web, and never use uploadfs;
  • without the file, the route answers 200 with "Page asset missing", which web_test_suite.py reports;
  • an OTA reformats the LittleFS, so upload again after one.

Not verified on hardware

There is no Pico W on the rig; its board is a Pico 2 W since 2026-10-22. When one is on the rig:

  • flash this image, upload data/web/license.html.gz, and run web_test_suite.py: /license must load from the file;
  • without the upload, it must report "Page asset missing".

🤖 Generated with Claude Code

https://claude.ai/code/session_01Uy7K2mzEmmjBnpxpdYNDFu

Ângelo Moisés Alves and others added 2 commits October 28, 2026 14:39
…tleFS, for 3,699 B of room under the OTA ceiling

pico_w_test (the bench image with the full CLI, not published; its manifest
comment says to take room from this image, never from the release) signs at
1,040,309 B on main 9f4da77 against the OTA ceiling of 1,040,384 B: 75 B of room
(763 B at 2075b84; #294 and #295 took 688 B). The UI-drivers branch, after its
sync with main, is 101 B over. The maintainer chose "open room in pico_w_test" by
the means #288 used for pico_w_test_https (2075b84): LICENSE_PAGE in
custom_fs_pages, so the page's gzip is served from /web/ on LittleFS.
pico_w_test_https extends this profile and keeps its own list, which already had
the page: its generated section is byte for byte main's.

Measured, all nine built from scratch on 9f4da77 plus this change (the pio shim
of this machine, one build at a time, check_flash_budget.py right after each):
- pico_w_test: flash used 1,028,036 -> 1,024,412 B (-3,624), .bin 1,040,068 ->
  1,036,444 B (sha256 c92bd240 -> 87dac855), signed 1,036,685 B, room under the
  ceiling 75 -> 3,699 B (the branch's 101 B over would become 3,523 B of room:
  arithmetic, not a build). RAM 109,212 B unchanged. Two builds of the tree give
  one sha256. Still under one 4 KiB sector, so the gate's WARN stays.
- Why -3,624 B and not the page's 4,260 B: nothing in this image was served from a
  file before, so the linker had dropped serveProtectedFsPage( ). nm -S -C of
  main's ELF against this one: LICENSE_PAGE_GZ -4,260 B (gone), serveProtectedFsPage( )
  +428 B (linked now), handleLicense( ) 24 -> 16 B; no other symbol changes size.
  Those make -3,840 B; the other +216 B are the "Page asset missing" notice and the
  file name in .rodata (+212 B, from a diff of the strings of the two .bin) and 4 B
  of .text outside any symbol (size -A: .text +424, .rodata -4,048).
  pico_w_test_https lost 4,256 B in #288 because it already linked the route.
- The other eight are byte for byte main's (sha256 of firmware.bin against the
  table of the base build; their ELFs equal its ELFs, too):
    pico_w_release    af3711c7c27df592b77ca7163c783471f6e7d9c8ad906ce8ebc089f872f84233  1035620
    pico_w_test_https c67194e81d3552af57a0b630d5314b666331ae6b5a589d4ba16dd397ffd631ec  1040876
    pico_w_asserts    81aa53d861273deb8ce04aed110442f21385ad66c79355fae5dcb4d0ac8f7cf7  1037924
    pico_w_alpha      b5d7d079db25cab25e37e2f60df2319f2018383324e35dfad4495d064adaa2d8  990380
    pico_w_air        4291184e6e1609db51bf820819ddcacdd628901052a5a1f2b74031a000cd8555  1035340
    pico2_w_release   42564ce8e0be271887da13d1b3d6f925c6d43ed8702458d77909e7b18c5d9c8c  999720
    pico_wire         3438b89af5e3036564e323430a417a0f1455cb26562941349b38b346cf6cee03  604336
    pico_wiretft      471e41929fa44bd0dd7ae82ff0134590238d8fbd53ce175ebcd185ead1c91157  787336
- tools/flash_budget.json: pico_w_test budget and measured -> 1,024,412, bin ->
  1,036,444; the row of PLANO_STABLE 3.1 reads 1.036.685 / 3.699.
- check_flash_budget.py on all nine (pico_w_test OK, with the WARN above; the other
  eight with their records unchanged), --table, test_flash_budget.py (24 ok),
  gen_features.py --check (rc 1 with features.toml edited and profiles.ini stale,
  rc 0 after regenerating; profiles.ini gains one line, in [env:pico_w_test]),
  check_features.py, test_build_custom.py, check_readme_numbers.py,
  check_angulo.py, and the 41 python commands of the CI gates job (rc 0 each, as
  on main) pass. The pio test suites were not run: no source file changed.

The deploy step grows with it, for both bench images. The build leaves
data/web/license.html.gz (4,260 B) and, for pico_w_test_https, alarms, files and
telemetry besides; the env built last decides what is left there. Until now the
requirement was written in the manifest comment of pico_w_test_https only;
AGENTS.md (Gravar firmware) says it once for both: upload to /web/ with
POST /api/upload?uploadDir=/web, never uploadfs; without the file the route
answers 200 with "Page asset missing", which web_test_suite.py reports; an OTA
reformats the LittleFS, so upload again after it.

Not verified on hardware: no Pico W on the rig (the rig's board is a Pico 2 W
since 2026-10-22). The check for when one is: flash this image, upload
data/web/license.html.gz, and run web_test_suite.py: /license must load from the
file, and without the upload it must report "Page asset missing".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Uy7K2mzEmmjBnpxpdYNDFu
…ml.gz, the file the build writes

The comment of pico_w_test_https told the bench to upload data/web/{alarms,files,tel,license}.html.gz;
tools/build_webui_gz.py:180 writes TEL_PAGE as telemetry.html.gz, so "tel.html.gz" never exists. One word,
found while moving pico_w_test's licence page to LittleFS in the commit before.

A comment of the manifest: gen_features.py --check passes with the generated files untouched (comments do
not reach profiles.ini), check_features.py passes (with this machine's pio shim in PATH), check_angulo.py
passes. No image byte can change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Uy7K2mzEmmjBnpxpdYNDFu
@github-actions github-actions Bot added documentation Improvements or additions to documentation tools Build tools, scripts, and developer tooling labels Oct 28, 2026
@angeloINTJ
angeloINTJ merged commit 99e9001 into main Oct 28, 2026
13 checks passed
angeloINTJ pushed a commit that referenced this pull request Oct 28, 2026
First parent: abf43e3 (C5). What lands from main: PR #297 (9eb4252, 8a38cbc): pico_w_test serves its licence page from LittleFS (custom_fs_pages = ["LICENSE_PAGE"]
in tools/features.toml, generated into tools/generated/profiles.ini), which opens room under the OTA ceiling; the AGENTS.md bullet on the pages that pico_w_test and
pico_w_test_https keep on LittleFS; main's row and numbers for the image in PLANO_STABLE.md and flash_budget.json.

Conflicts (2), as resolved
- docs/analysis/PLANO_STABLE.md: both sides changed the pico_w_test row of section 3.1 (C1's -101 B; main's 3.699 B of room, measured on main's own tree). The table is the
  branch's, and the row is the one tools_s10c/budget_set.py writes from this merge's build: | pico_w_test | 1.036.853 | 3.531 |, the line the gate itself prints. C5's bullet
  ("over the ceiling on this branch") is now one dated line in the past: 101 B over after C1, cleared by #297 at this merge.
- tools/flash_budget.json: the branch's file, then main's two added sentences (measured_on, measured_at_commit), then this merge's (budget_set.py's sentence and a
  measured_at_commit entry). pico_w_test's budget, measured and bin come from this merge's build, not from either side: main's were measured on main's tree (1,024,412 and
  .bin 1,036,444), the branch's before #297 (1,028,212 and .bin 1,040,244).
Merged clean: AGENTS.md (main's bullet is about pico_w_test and pico_w_test_https only; re-read, nothing on this branch contradicts it), tools/features.toml and
tools/generated/profiles.ini. profiles.ini is not edited here: python3 tools/gen_features.py --check says the generated files are up to date.

pico_w_test's numbers (from the build, 2026-10-28; the expectation written before it was about -3,624 B)
- .bin 1,040,244 -> 1,036,612 B (-3,632; main's own pair was 1,040,068 -> 1,036,444, -3,624); flash used 1,028,212 -> 1,024,580; signed 1,036,853 B, 3,531 B under the OTA
  ceiling of 1,040,384 B (it was 101 B over from C1 to C5). The gate's WARN stays: under one 4 KiB sector.
- By nm -S exactly three symbols differ from C5's image, main's three: WebManager::handleLicense() 24 -> 16 B, WebManager::serveProtectedFsPage(unsigned short, char const*)
  new, 428 B, WebUI_GZ::LICENSE_PAGE_GZ 4,267 B gone. elf_funcoes + reloc_only name the same, plus _fini's padding (2 -> 3 instructions, a link artifact); the notice
  "Page asset missing" and "/web/license.html.gz" are the new text in .rodata (cmp_c5/summary.txt).

Proofs (host only; records in stages/sync6b)
- The eleven images from scratch (shim first in PATH, no PLATFORMIO_*, under flock): ten sha256-equal to C5's, pico_w_test_https included (#297 left its generated section as
  it was); pico_w_test is the only one that changed.
- check_flash_budget.py right after each of the eleven builds: exit 0 for all eleven. pico_w_test exited 1 from C1 to C5; it exits 0 now, with the WARN above.
- After budget_set.py: check_flash_budget.py pico_w_test exit 0 with no NOTE; --table OK (11 images, 1 exempt); test_flash_budget.py 24 ok; gen_features.py --check, check_features.py
  (it calls pio: the shim), check_readme_numbers.py (764 cases) and check_angulo.py exit 0; git diff --cached --check clean; no conflict marker anywhere.
- The instrument: budget_set.py could not read a row with a negative headroom (its row regex took digits only, and the table had -101); the regex now takes a minus sign (the old
  file is tools_s10c/budget_set.py.antes_sync6b), and the row it writes equals the one the gate prints.
- Not done here: pico_w_test now answers /license with "Page asset missing" until data/web/license.html.gz is uploaded to /web/ (AGENTS.md's new bullet).

Not verified on hardware.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Uy7K2mzEmmjBnpxpdYNDFu
@angeloINTJ angeloINTJ mentioned this pull request Oct 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation tools Build tools, scripts, and developer tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant