Skip to content

Commit e8272ef

Browse files
CrispStrobeclaude
andcommitted
docs: rewrite README + EV3dev bridge guide so a fresh user can succeed
Three doc updates that capture everything we learned from the 2026-05-05 hardware validation pass: - **README.md**: top-down rewrite around a "I just want it to work" decision table that maps brick + platform → guide. Adds an EV3dev 90-second quick-start with the right launcher (PYTHONIOENCODING=utf-8, python3 -u) so a clean restart doesn't hit the locale crash. Documents the iOS `NSAllowsLocalNetworking` ATS pattern (App-Store-friendly, unlike `NSAllowsArbitraryLoads`). - **README_ev3dev_bridge.md**: rewritten end-to-end for v2.3.1. - Replaces stale 192.168.178.50 examples with `<brick-ip>` placeholder. - Drops the obsolete `--ssl` flag (now dual-mode by default) in favor of `--http-only` / `--https-only`. - Adds the recipe to regenerate the cert when the brick's IP changes (delete `/home/robot/ev3.{crt,key}` and restart). - Documents the three latent bugs (f-strings on Py 3.5.3, ASCII upload codec, locale crash in cert-gen log) in their own section so anyone deploying knows what failure modes to watch for. - Step-by-step macOS install that's been verified end-to-end (separate `sudo` lines so any error is visible; `find-certificate` verification; explicit Safari ⌘Q reminder). - Clarifies that macOS curl reads `/etc/ssl/cert.pem` first and Keychain second — explains why a working install can still fail `curl https://...` if you fight the wrong test. - Three-step iOS walk-through that emphasises the Settings → General → About → Certificate Trust Settings step (the one almost everyone misses). - App Store ATS section: `NSAllowsLocalNetworking` + the iOS 14+ `NSLocalNetworkUsageDescription` purpose string, with rationale for why `NSAllowsArbitraryLoads` is the wrong choice. - systemd unit file now sets `PYTHONIOENCODING=utf-8` and runs `python3 -u`. - **PLAN.md**: marks Phase 5 (hardware validation) complete for ev3dev with link to the LEARNINGS.md section. Spike / NXT / LMS hardware validation explicitly deferred. Adds the bridge bugs as "out-of-band fixes deferred" alongside the existing pre-existing items (cert-IP-mismatch heuristic, running_scripts reaping). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 9af6093 commit e8272ef

3 files changed

Lines changed: 728 additions & 546 deletions

File tree

PLAN.md

Lines changed: 84 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,13 @@ on the
1515
branch — these are the **completed Phase 2 + Phase 4 audit deliverables**
1616
described in `LEARNINGS.md` (operators / lists / procedures / keypress
1717
wiring / `control_wait_until` / repeat_until yield, across `ev3dev_py`,
18-
`legospike`, `legonxt`, and `ev3_lms`). They pass `node --check` but are
19-
**untested on hardware**. They were authored against an older sandbox copy
20-
that lagged the gallery — porting needs a 3-way merge (gallery main +
21-
sandbox-base + WIP) per file, then hardware validation, before the audit
22-
fixes can land in the gallery.
18+
`legospike`, `legonxt`, and `ev3_lms`). They pass `node --check` and as of
19+
**2026-05-05 are hardware-validated for ev3dev** (44/44 emitted-pattern
20+
smoke-test cases pass on a real brick — see
21+
[`LEARNINGS.md` § Hardware validation](./LEARNINGS.md#hardware-validation-on-the-brick--three-bridge-bugs-found-2026-05-05)).
22+
Spike Prime / NXT / LMS hardware validation is still deferred. Porting
23+
into the gallery still needs a 3-way merge (gallery main + sandbox-base
24+
+ WIP) per file.
2325

2426
```bash
2527
# rough porting recipe per file
@@ -34,46 +36,102 @@ What stayed here:
3436

3537
| Category | What lives here |
3638
|----------|-----------------|
37-
| **EV3 host bridges** | `ev3dev_ondevice.py` (2865), `ev3_local_bridge.py` (788) |
39+
| **EV3 host bridges** | `ev3dev_ondevice.py` (~2940 LOC, v2.3.1 as of 2026-05-05), `ev3_local_bridge.py` (~790 LOC) |
3840
| **EV3 compile service** | `ev3-compiler-service/` — Flask app + bundled `lmsasm-binary` (3.7 MB) used by the gallery's `ev3_lms_transpile.js` |
39-
| **NXT bridges + tools** | `nxt_bridge.py` (673), `nxt-pybluez-bridge.py` (335), `nxt-diag.py` (127), `test_bt.py`, `reset_nxt.sh` |
40-
| **Generic bridges** | `lego_bridge.py` (1002), `lego_bridge_unified.py` (318), `universal_bridge.py` (774), `universal_lego_bridge.py` (1851) |
41+
| **NXT bridges + tools** | `nxt_bridge.py` (~673 LOC), `nxt-pybluez-bridge.py` (~335 LOC), `nxt-diag.py` (~127 LOC), `test_bt.py`, `reset_nxt.sh` |
42+
| **Generic bridges** | `lego_bridge.py` (~1000 LOC), `lego_bridge_unified.py` (~318 LOC), `universal_bridge.py` (~774 LOC), `universal_lego_bridge.py` (~1851 LOC) |
4143
| **Top-level docs** | `README.md`, `README_bridges.md`, `README_ev3_local_bridge.md`, `README_ev3dev_bridge.md` |
4244
| **Audit notes** | `PLAN.md` (this file), `LEARNINGS.md` |
4345
| **`bkp/`** | Historical/experimental versions. Not loaded. Do not audit. |
4446

4547
Note: `ev3dev_ondevice.py` (here) and `ev3_bridge.py` (gallery) are two
46-
versions of the same on-device bridge that have drifted independently —
47-
2865 vs 2074 lines, both have unique content. Reconciling them is a
48-
separate task from this audit.
48+
versions of the same on-device bridge that have drifted independently.
49+
Reconciling them is a separate task from this audit.
4950

5051
## Audit target
5152

5253
`extensions/CrispStrobe/ev3dev_py_transpile.js` in the gallery
5354
(<https://github.com/CrispStrobe/extensions/blob/main/extensions/CrispStrobe/ev3dev_py_transpile.js>).
5455
Other transpilers (`ev3_lms_transpile.js`, `legonxt_transpile_universal.js`,
55-
`legospike_turbowarp_transpile.js`) likely share the same gaps and will be
56-
worth a follow-up audit using the same checklist.
56+
`legospike_turbowarp_transpile.js`) share the same gaps and got the same
57+
checklist applied.
5758

5859
## Audit phases
5960

60-
### Phase 1 — Coverage audit (current)
61-
Build a canonical Scratch generic-flow opcode list from `scratch-vm/src/blocks/`
62-
(control / event / operators / data / procedures / sensing). Grep the EV3dev
63-
transpiler for each. Output: gap table — opcode, presence, partial, semantics.
61+
### Phase 1 — Coverage audit ✅
62+
Built a canonical Scratch generic-flow opcode list from
63+
`scratch-vm/src/blocks/` (control / event / operators / data / procedures
64+
/ sensing). Grepped each transpiler for each. Output: gap table. **Done
65+
for all four transpilers.**
6466

65-
### Phase 2 — Semantic audit
66-
For each handled-but-risky block, trace it end-to-end through the transpiler:
67+
### Phase 2 — Semantic audit + initial fixes (ev3dev) ✅
68+
For each handled-but-risky block, traced end-to-end:
6769

6870
- `event_broadcast` vs `event_broadcastandwait` (must wait!)
69-
- `control_wait_until`, `control_repeat_until`
71+
- `control_wait_until`, `control_repeat_until` yield
7072
- `procedures_definition` "run without screen refresh" (warp)
7173
- `control_stop` (this script / other scripts in sprite / all)
72-
- `control_start_as_clone`, `control_create_clone_of`, `control_delete_this_clone`
73-
- Variable / list scope (sprite-local vs. global) — Python output must reflect this
74+
- `control_start_as_clone`, `control_create_clone_of`,
75+
`control_delete_this_clone`
76+
- Variable / list scope (sprite-local vs. global)
7477
- Yields inside loops (does emitted Python actually let other scripts run?)
75-
- Hat blocks beyond `event_whenflagclicked` / `event_whenbroadcastreceived`
78+
- Hat blocks beyond `event_whenflagclicked` /
79+
`event_whenbroadcastreceived`
7680

77-
### Phase 3 — Targeted fixes
78-
Address gaps and inconsistencies surfaced in 1+2. One PR-shaped change at a
79-
time, against `CrispStrobe/extensions:main`.
81+
**ev3dev fixes landed** (operators round/mod/mathop/letter_of/length/
82+
contains, lists with helpers, procedures with arg_*, keypress wired to
83+
brick buttons, control_wait_until, repeat_until yield, unknown-hat warning).
84+
85+
### Phase 3 — Coverage audit of Spike / NXT / LMS ✅
86+
Same Phase 1 checklist applied to the three siblings. Each has the same
87+
broad gaps; only operator menus and hat-dispatch differ. **Done.**
88+
89+
### Phase 4 — Targeted fixes for Spike / NXT / LMS ✅
90+
- **Spike** got the full Phase-2 mirror in MicroPython idioms (lists,
91+
procedures, missing operators, control_wait_until, repeat_until yield;
92+
keypress emits an honest warning since Spike's runtime is
93+
single-threaded).
94+
- **LMS** got `control_wait_until` (loop with `TIMER_WAIT`); other gaps
95+
deferred until a real user need surfaces (LMS bytecode has no native
96+
callable-function abstraction).
97+
- **NXT** got `control_wait_until` (NXC `while(!cond) Wait(10);`).
98+
Pre-existing `pendingRequests` FIFO bug picked up from upstream sync.
99+
100+
All four files pass `node --check` and were on the
101+
`wip-pre-collapse` branch awaiting hardware validation.
102+
103+
### Phase 5 — Hardware validation ✅ (ev3dev only) / ⏳ (others)
104+
105+
**ev3dev (2026-05-05):** 44/44 audit-fix smoke-test cases PASS on a real
106+
brick at `192.168.178.57`. The smoke test reproduced the **exact** Python
107+
the WIP transpiler emits (`_list_*` helpers, `int(math.floor(float(x) +
108+
0.5))` for round, `math.sin(math.radians(x))` for trig, the
109+
procedure-as-Python-def pattern with `arg_<sanitized>` parameters, the
110+
busy-loop with `time.sleep(0.01)` yield) and uploaded it via the bridge's
111+
`upload_script` + `run_script` API. Surfaced three latent bugs in the
112+
bridge itself (f-strings on a Python 3.5.3 host, ASCII codec on
113+
upload_script, locale crash in cert-gen log lines) which were fixed +
114+
landed as bridge v2.3.1. See `LEARNINGS.md` for the full picture.
115+
116+
**Spike Prime:** still deferred until a hub is plugged in.
117+
**NXT:** still deferred until a brick is paired up.
118+
**LMS:** still deferred (mostly relevant when the
119+
`legacy-lego-compiler` REST API is exercised end-to-end).
120+
121+
### Phase 6 — Port WIP into the gallery ⏳
122+
123+
Once hardware validation is done for the relevant target, run the 3-way
124+
merge recipe at the top of this file to land the WIP transpiler into
125+
`CrispStrobe/extensions:main`. ev3dev is unblocked; the other three are
126+
not.
127+
128+
## Out-of-band fixes deferred for later
129+
130+
- Reconcile `ev3dev_ondevice.py` (here) ↔ `ev3_bridge.py` (gallery).
131+
- Auto-regenerate the bridge's self-signed cert when the brick's IP is
132+
no longer in the SAN list.
133+
- Reap `running_scripts` dict entries when their subprocess exits.
134+
- A shared "scratch-vm-flow" core to replace the four near-copy
135+
transpilers (cuts surface area to ~25%, but a lot of churn).
136+
- Python 3.5 lint job in CI to catch f-string regressions in the bridge
137+
(the existing ruff job runs on a 3.10+ runner).

0 commit comments

Comments
 (0)