Repository navigation
Description
Handoff for the next agent picking up the RP2350W / port-diagnostics thread. Written at the end of a long session so the context does not have to be re-derived.
1. The thing most likely to waste your time
health=phantom in fbuild port scan means the hardware is NOT ATTACHED. It is a leftover Windows registry record, not a broken device.
This cost this session hours. The RP2350W was reported (in #3864) as a wedged devnode needing BOOTSEL and scoped PnP recovery. Windows actually said Present = False, last seen six days earlier. It simply was not plugged in. Compounding it, a genuinely descriptor-failed board (code 43) sat on a different root port, and conflating the two produced the "wedged" reading.
Before attempting any recovery:
Get-PnpDevice -Class Ports | Select-Object Status, Present, FriendlyName
Get-PnpDeviceProperty -InstanceId '<instance>' -KeyName DEVPKEY_Device_LastArrivalDatefbuild port doctor (now on main) answers this in one command. Use it first.
Absent hardware and broken hardware look identical in a port scan and need opposite responses. --admin PnP recovery on an absent device is a no-op.
2. Current state
Merged to fbuild main:
- feat(port): fbuild port doctor — diagnose port presence/health, with a safe --fix #1280 (
eef651e7) —present=noinscan;fbuild port doctor; suspend-policy reporting - fix(teensy): run the link in the build dir, not the inherited cwd #1268 / fix(arm): run the link in the build dir for every ARM linker (#1269) #1270 — ARM link runs in the build dir (fixed the stray
-rfile) - fix(rp): honor Arduino Bluetooth menu #1263 — Arduino-Pico Bluetooth menu; shipped in fbuild 2.5.15, pinned in FastLED#3871
Open:
- feat(port): add
doctor --fixfor USB selective suspend #1281 —doctor --fix(this was pushed to feat(port): fbuild port doctor — diagnose port presence/health, with a safe --fix #1280's branch after it merged, so it missed the train; rebased onto main) - feat(port): fbuild port doctor — diagnose port presence/health/power policy, with a safe --fix #1279 — the parent issue, still open; see remaining scope below
FastLED side: #3866 (teensy set_audioClock), #3869 (esp32p4 h264), #3871 (fbuild 2.5.15 pin), #3872 (autoresearch selective-suspend preflight) all merged. #3838 reopened (2 of 3 failure classes remain, upstream). #3870 filed (esp32dev 72KB over budget, not started).
3. Remaining scope on #1279
Not done, roughly in value order:
scanfooter +suspend=per port. Nobody reads--helpfor a subcommand they do not know exists; surfacingdoctorwhere people already look is most of the value. Cheapest item here.- Per-device suspend state. Only the plan-level setting is handled. The per-device layer lives at
HKLM\SYSTEM\CurrentControlSet\Enum\<id>\Properties\...(DeviceIdleEnabled,DefaultIdleState,DefaultIdleTimeout). Until this exists,--fixcannot round-trip prior per-device state as the acceptance criteria require. --json, and--all/--hubscope selectors.last-seen=<age>— see the dead ends below.
4. Dead ends — do not repeat these
last-seen / DEVPKEY_Device_LastArrivalDate. I implemented it, could not make it work, and removed it rather than ship a field that silently returns None:
SetupDiGetDevicePropertyWon the devinfo set returns nothing for a phantom devnode.- The iterator's
DevInstis invalid for phantoms by construction —CM_Get_DevNode_StatusreturningCR_NO_SUCH_DEVINSTis exactly howpnp_observationclassifies one. CM_Locate_DevNodeW(..., CM_LOCATE_DEVNODE_PHANTOM)succeeds (cr=0x0) but the follow-upCM_Get_DevNode_PropertyWreturnscr=0x25(CR_NO_SUCH_VALUE), and the returneddevinst=1looks like the root node rather than the target.- The registry copy under
...\Properties\{540b947e-8b40-45bc-a8a2-6a0b894cbda2}\0066exists but needs elevation, which conflicts withdoctorbeing read-only. - PowerShell's
Get-PnpDevicePropertyreturns it unelevated, so a working path exists — I did not find it. Start by tracing what PowerShell actually calls.
uhubctl on Windows. Does not work — libusb's winusb.sys cannot issue the required control requests. A software VBUS cycle is impossible on Windows without hardware.
Bus reset ≠ VBUS cycle. Device disable/enable and root-hub restart do not recover a descriptor-failed device. This was tried repeatedly on the RP2040 IM411 board (code 43 since mid-July) and never worked. Do not add it to --fix.
5. Local/CI parity (fbuild)
Near-miss reproductions cost two CI cycles this session. Use the exact commands:
soldr cargo clippy --workspace --all-targets -- -D warnings # the trailing -- -D warnings is load-bearing
soldr cargo fmt --check
uv run python ci/find_direct_subprocess.py --fail
- Do not use
RUSTFLAGS="-D warnings"— it applies to dependencies and breaks their builds; CI never does that (--cap-lints allow). - MSRV is 1.75, not 1.94. The root
.clippy.tomlpinsmsrv = "1.75"and overridesCargo.toml'srust-version = "1.94.1". Anything stabilised after 1.75 tripsclippy::incompatible_msrv.Option::is_none_or(1.82) bit me. - Every subprocess must go through
fbuild-core::subprocesswrappers, or carry// allow-direct-spawn: <reason>.run_command_blockingis the sync one. - 1000-LOC cap per
.rsfile — put new commands in their own module. - A bare
cargoanywhere in a Bash command, including inside a commit message, trips therust_tool_guardhook. Usegit commit -F <file>.
6. RP2350W HIL (FastLED#3864) — still blocked, but only on hardware
Blocker 1 (unreleased fbuild) is resolved: 2.5.15 shipped and is pinned; bash compile rp2350w --examples AutoResearch builds from a clean checkout (flash 1177936, ram 132048).
Remaining, both physical:
- The RP2350W (
2E8A:F00F, serial2DCB876B587EA334) does not enumerate. A replug was attempted and no new device node appeared at all — not even a code-43 one — so try a different cable and a direct root port rather than the Genesys hub it was on. - No ESP32-C6 has ever been attached on this host. The only Espressif device present is an S3 (
303A:1001/8C:BF:EA:CF:87:B4) on COM9.--net-peerand--otacannot run without a real C6.
Also: #3864's five handoff commands all pass --upload-port COM17. Drop it. For RP-series that pins deploy to one record and defeats fbuild's own exclusion of unhealthy CDC records plus its BOOTSEL-volume fallback (#1147). Use --upload-port UF2=<volume> if the board is in BOOTSEL with no working CDC.
7. Two process notes
Verify against real hardware, not just tests. Two bugs this session passed their unit tests while being completely broken in practice: a capture_output=False default that left a probe silently returning nothing, and the last-seen property that always returned None. Both were caught only by running the thing. Mocked tests cannot catch a wrong API call.
A merged PR's branch is not a safe place to push. #1281 exists because I pushed a commit to #1280's branch minutes after it merged. git push succeeded, the branch ref updated, but the PR head stayed frozen and no CI ran — which looks exactly like GitHub lag. Check gh pr view --json state before assuming a push will be picked up.
Related
- feat(port): fbuild port doctor — diagnose port presence/health/power policy, with a safe --fix #1279, feat(port): fbuild port doctor — diagnose port presence/health, with a safe --fix #1280, feat(port): add
doctor --fixfor USB selective suspend #1281, fix(rp2040): reject phantom CDC ports and give recoverable BOOTSEL guidance #1147, QEMU toolchain: qemu-system-xtensa fails with 'libslirp.so.0: cannot open shared object file' (exit 127) #1266 - chore(rp2350w): hand off final #3832 hardware validation FastLED#3864, #3832, #3838, #3867, #3870, #3872
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsTriage
Activity
zackees commentedon Aug 7, 2026
Update: the
last-seendead end has a way throughSection 4 says a working unelevated path exists but I had not found it. I have now — recording it so the next attempt starts from the answer rather than the Win32 API rabbit hole.
Get-PnpDevicePropertyreads it unelevated, for phantom devices, today:So the CIM path succeeds where all four Win32 approaches failed. That means no new Rust FFI is needed — this can reuse the same PowerShell-through-
fbuild_core::subprocesspattern already used forpowercfgandMSPower_DeviceEnable.The catch, measured
Get-PnpDevicePropertyper deviceGet-PnpDevicePropertyis ~0.74 s per device and does not batch across devices, so the full listing is not viable.Win32_PnPEntitydoes not expose the property, and the registry copy still needs elevation.Therefore
Implement
last-seenonly when--portis given — one call, both keys, ~725 ms. That is precisely the case where someone is asking "is this board broken or just unplugged?", so the information lands where it is wanted. Omit it from the all-ports listing rather than paying 12.5 s, and say so in the output rather than silently dropping it.Same shape as the per-device suspend decision: a diagnostic can afford ~1 s for a targeted question; a listing cannot.
Convert
Datawith([DateTimeOffset]$d.Data).ToUnixTimeSeconds()and parse the integer Rust-side — that sidesteps locale-dependent date formatting entirely.feat(port): per-device suspend state in doctor
feat(port): report last-seen for a targeted port
feat(port): add --all and --hub scope selectors to doctor
feat(port): per-device suspend state in doctor
feat(port): report last-seen for a targeted port
feat(port): add --all and --hub scope selectors to doctor
feat(port): scan footer pointing at doctor, and doctor --json (#1283)
feat(port): per-device suspend state in doctor
feat(port): report last-seen for a targeted port
feat(port): add --all and --hub scope selectors to doctor
feat(port): per-device suspend, last-seen, and --all/--hub selectors (#…
zackees commentedon Aug 7, 2026
The port-diagnostics half of this handoff is complete — #1279 closed via #1280, #1281, #1283, #1284 (all merged).
What changed since this was written
§4's
last-seendead end has a way through, and it is implemented. The four Win32 approaches all fail for phantom devnodes as documented, but the CIM provider behindGet-PnpDevicePropertyanswers unelevated, for phantoms. No new FFI — it reuses the PowerShell-through-fbuild_core::subprocesspattern. Measured ~0.74 s/device with no batching, so it runs only for--port.§1's lesson is now enforced by the tool.
fbuild port doctorstates in one command that a board is not attached, when it was last seen, and that a stale record is not a fault — and keeps unassociated code-43 devices in their own section so they are never blamed on the wrong port.§5's local/CI parity notes held up and earned their keep: the
-- -D warningsrequirement and the 1.75 clippy MSRV each cost a CI cycle before I applied them. Two additions worth carrying forward:port_doctor.rscrossed it at 1041 and had to be split.in_reply_to_id), not a PR-level comment.Still open from this handoff
The RP2350W HIL work (FastLED/FastLED#3864) is untouched and still blocked on physical hardware:
2E8A:F00F/2DCB876B587EA334) does not enumerate. A replug produced no new device node at all — not even a code-43 one — so try a different cable and a direct root port rather than the Genesys hub.--net-peer/--otacannot run without one.--upload-port COM17from #3864's five commands; for RP-series it defeats fbuild's own BOOTSEL fallback (fix(rp2040): reject phantom CDC ports and give recoverable BOOTSEL guidance #1147).fbuild port doctor --port COM17now reports exactly that state, which is the check to run first next time.Closing this as a handoff; the hardware work continues on FastLED/FastLED#3864.