feat: the build configurator page (docs/configurador/) - #187
Merged
Merged
Conversation
The page P7 promised, on the backend of #186: pick a product, switch features on or off in a tree grouped by what they are, see whether the image fits, and compile it. English and Portuguese, both themes, installable as an app, in the Ângulo standard. What the page does: - Products as selectable cards; the switches in one card per group, each with its help text and its measured price on that product ("148.9 KB" for Bluetooth on SIMUT, "134.3 KB" on Air). - A switch a rule forbids is locked, with the rule's reason in words. A switch the matrix found to change nothing on that product (`same`) says so instead of showing +0 B. - The result: flash used against the slot and .bin against the OTA ceiling, with the fit as a selo (Fits, Tight, Does not fit), the RAM figure, the rules broken and the hazards lit. It is labelled an estimate, and the note says how far the sum missed the 8 real combined builds (up to 4,392 B of flash, 8,192 B of .bin); "Tight" starts that far from a ceiling, derived from the data, not typed. - Compile this build: dispatches build-custom.yml with the reader's token, finds the run by its title, follows it, and reads the measured sizes back from the artifact's name. Request this build: a pre-filled issue with the profile, for anyone without write access. Copy link: the choice lives in the URL (#b=...&on=...&off=...), parsed strictly. - On a phone, a bar keeps the figure in sight while the tree scrolls. Safety: text from the model, the link and the GitHub API is set as textContent only; a Content-Security-Policy allows scripts from the page alone and connections to api.github.com alone; the token is kept for the session unless the reader asks to remember it, and goes nowhere else; a run link from the API is used only if it points at this repository's runs. The service worker revalidates every request, so a new model.json never meets a stale app.js inside GitHub Pages' ten-minute cache. Supporting changes: tools/gen_logo.py draws the three app icons from the tokens (a maskable one included); tools/check_angulo.py now reads the page's CSS and checks that each standalone page carries the generated brand and that the app manifest names token colours (4 of 4 by mutation); the language switch moved from the landing's <style> to site.css, which both pages load; the landing's "Download the firmware" step links here; build.json records the commit the build came from (the Actions checkout is shallow, so "last commit touching src" was HEAD there anyway). Verified: - tools/test_configurator_page.py runs logic.js under node against the generated model: 468 profiles and links spelled as build_custom.py spells them, 66 single-switch estimates equal to the matrix, 66 locks equal to rule_violations, 9 hostile links refused. Negative controls: a profile with its keys out of order, a lock that never locks, a link that takes an unknown switch, each caught. - In Chrome, at 390, 927 and 1280 px, both themes, both languages: no horizontal overflow; locks, prices and the fit selo right on all three products; the GitHub flow against a mocked API (no request left the machine): success with sizes read from the artifact name, a 401, a profile refused by the workflow, and a run link from another host dropped. - End to end on the real workflow (run 36273093811, Air without Bluetooth): artifact simut-...-bin877604-ram100796, .bin b199d20e and .uf2 8f6404c0, byte-identical to the same profile built on this machine. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Jq4auDQppGzmAx1gLKn1z3
…passes tools/scan_secrets.sh reads `NAME...TOKEN = "six or more characters"` as a literal credential, and docs/configurador/app.js had `const TOKEN_KEY = "simut:configurador:token"` — the localStorage key the token is kept under, not a token. The allowlist is for credentials published on purpose, which this is not, so the constant is renamed STORAGE_KEY instead. Every gates-job step now passes locally, in CI order. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Jq4auDQppGzmAx1gLKn1z3
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
This is the build configurator page, the last piece of P7, on top of the backend from #186. It lives at
https://angelointj.github.io/simut/configurador/once merged. English and Portuguese, both themes, installable as an app, in the Ângulo standard.same) says so instead of showing +0 B..binagainst the OTA ceiling, with a fit selo: Fits, Tight or Does not fit. The card also shows the RAM figure, broken rules and lit hazards. It is labelled an estimate, and its note gives the measured error of the sum over the 8 real combined builds: up to 4,392 B of flash and 8,192 B of.bin. The "Tight" margin comes from that data.build-custom.yml, finds the run by its title, follows it, and reads the sizes back from the artifact name.Supporting changes:
gen_logo.pydraws the three app icons from the tokens.check_angulo.pynow reads the page's CSS, checks that the standalone pages carry the generated brand, and checks that the app manifest names token colours (4 of 4 by mutation).site.css.build.jsonrecords the commit the build came from.Verified
test_configurator_page.py(gates job) runslogic.jsunder node against the generated model:build_custom.pyspells them;rule_violations;Negative controls: keys out of order, a lock that never locks, and a link that takes an unknown switch are each caught.
Chrome, at 390, 927 and 1280 px, in both themes and both languages:
End to end on the real workflow (run 36273093811, Air without Bluetooth): artifact
…-bin877604-ram100796. Its.bin(b199d20e) and.uf2(8f6404c0) are byte-identical to the same profile built locally.Not verified: the compile button with a real token. That needs the maintainer's own fine-grained token (Actions: read and write, this repository only). The dispatch itself was proven with
gh workflow run, the same API call the page makes.Security (the six failures)
sessionStorageunless the reader ticks "Remember" (localStorage). It is only ever sent toapi.github.com, and the page asks for a short-lived token scoped to this repository. It is readable by any page served fromangelointj.github.io, and all of those belong to the owner.build_custom.pyre-validates the profile and re-applies the rules.textContent. The CSP allowsscript-src 'self'andconnect-src 'self' https://api.github.com, with no inline script and no style attributes. The hash is parsed strictly, and a run link is followed only if it points at this repository's runs.🤖 Generated with Claude Code
https://claude.ai/code/session_01Jq4auDQppGzmAx1gLKn1z3