summaryrefslogtreecommitdiff
path: root/.claude
AgeCommit message (Collapse)Author
2026-07-30hil, ci: scope HIL builds and tests to the boards a PR affects (#3797)Ha Thach
hil, ci: scope HIL builds and tests to the boards a PR affects Add test/hil/hil_select.py, a stdlib-only selector that maps a PR diff to the rig boards, tests and BSP families a change can affect, and wire it into CI so pull requests build and run only those. A port change picks its families' boards, a class change picks the examples enabling that class, and device/host changes prune the other role. Anything unclassified — infra, an unmapped port, a selector error — falls back to the full matrix, and push/schedule runs are untouched. Move the shared example lists to hil_examples.py; 54 hardware-free tests cover the rules.
2026-07-29hil: split hil_test.py into hil_lock/hil_flash, add pool_check, update rig ↵Ha Thach
probes (#3794) test/hil: add board-pool health check, split hil_test into focused modules (#3794) Add test/hil/hil_pool_check.py: per-board rig health scan — probe presence, light-example flash (dfu_runtime; device_info + serial check for host-only boards), uid re-enumeration, safe recovery (probe authorized-toggle, board reset), verified board_test re-park, USB topology report, and a markdown summary table. Missing firmware is built on the spot (tools/build.py, idf.py for espressif, one get_deps retry); row statuses: ok, flash-failed, failed, locked. Board locks are always respected, never bypassed. Refactor hil_test.py into hil_lock.py (flock protocol, controller permits, hold/release/status CLI; replaces board_lock.py) and hil_flash.py (flashers, find_firmware, run_cmd). Update WCH probe uids and the board roster in tinyusb.json; add the hil-pool-check skill.
2026-07-28test/hil: replace PCI reset with root-port VBUS cycle for D-state recovery ↵Ha Thach
(#3789) test/hil: replace PCI reset with root-port VBUS cycle for D-state recovery pci-reset was documented as an FLR, but no controller on either rig has FLR, so it issued a PCIe secondary bus reset on a live, driver-bound xHCI -- halting the card until the PVE host was power-cycled, and returning success so the caller could not tell. It destroyed the ci controller twice. Replace it with root-cycle, which cuts VBUS at the xHCI root port and touches only the root hub, so it never takes the per-device lock the wedged ioctl holds. uhubctl needs -S, or its sysfs backend disconnects the child before cutting power and blocks on that same lock. Success is proven by the device's sysfs directory inode changing: node existence proves nothing, and devnum is reused once the per-bus map wraps. usbtest.py's hang path invokes it, then confirms via /proc that nothing still holds the device node. Skill scripts now run from the repo; the drifted /usr/local/sbin copies are deleted.
2026-07-24address #3787 Codex round 3: coverage keys, RA attach limitationhathach
Coverage rows now resolve the de-collided module-qualified key introduced for same-named statics. RA boards: document that --attach requires a debugger-booted target - the C_DEBUGEN gate exists because an unguarded TRCKCR write bricks standalone boots (hardware-proven), so the limitation is documented rather than the guard weakened; a debugger-side TRCKCR hook can lift it later once re-verified on hardware. The stm32n6 board-gating suggestion is not taken: N6 trace pins are AF0-fixed chip-level, the same family-wide pattern as stm32h7.
2026-07-24address #3787 Codex round 2: board-gate PHY resets, session robustnesshathach
The board-specific PHY-reset nets move behind a board.h opt-in (TRACE_ETM_QUIET_ENET_PHY on same70_xplained and mimxrt1170_evkb) so other boards of those families cannot inherit a foreign GPIO write; the chip-level trace pin muxes stay family-wide by design (same pattern as stm32h7). same70 reference: width 1 is the validated default until the J403.16 rework, and the hooks now wait (bounded) for PCKRDY3 before Ozone arms trace. ra8m1 reference caches the boot ROM in AfterTargetConnect so --attach sessions decode ROM execution too. etm_capture rejects an unexpanded CMake JLINK_DEVICE with a clear error; PIO-USB + TRACE_ETM on RP2350 is now a compile error (48 MHz trace clock is too slow for PIO-USB and a runtime switch would desync the stream); etm_profile keeps same-named statics from different modules as distinct rows. Build-verified: same70_xplained, mimxrt1170_evkb, raspberry_pi_pico2.
2026-07-24address #3787 reviews: bsp fixes, script hardening, board-note accuracyhathach
Bot findings (Copilot/Codex): no-op board_trace_pinmux stubs for lpcxpresso18s37/43s67 (TRACE_ETM otherwise broke their build), SAME70 ID_PIOD clock enable, capture-script duplicate BeforeTargetConnect on the RA references, profile-script support for --no-timestamps itraces. Deep review (whole branch): same70_xplained board row + caveat restored, stale pico2 72 MHz claim corrected to the shipped 48, explicit SetTracePortWidth(4) in the three references that relied on Ozone's default, coverage-cell guard, median-based SysTick calibration, dead session flag removed, stale RA8M1 divider comment fixed (0x02 = /4 is the validated chip max) and the debugger guard indented. EVKB bench findings: only R1884/D3 remains open (D1/D2 meter-verified); RT1176 trace width is 1 or 4 only - J-Link arms the CSSYS TPIU and its own sampler at 4-bit for any width>=2 request; a powered MCU-Link USB breaks the external probe even with JP4 shorted.
2026-07-24imxrt: hold EVKB Ethernet PHY in reset while tracing, 50 MHz trace pinhathach
Fresh bring-up pass on mimxrt1170_evkb: holding the 100M RTL8201 in reset (ENET_RST_B = GPIO_LPSR_04) stops its RMII lines driving against the shared trace pads and doubles the clean trace-pin rate to 50 MHz (100 MHz CSTRACE root; 133 MHz root is marginal, stock 132 corrupts). Validated 3x 8 s TinyUSB captures at 11.46M fetches. D1-D3 remain silent in every configuration - the welded R1882-R1884 are electrically open; reflow is the remaining step to width 4. Board notes gain JP4 (must be shorted for an external probe on J58).
2026-07-24target-debug: list etm-trace as the instruction-level channelhathach
Fifth capture view alongside usbmon/kernel/target/wire: exact execution history via J-Trace, existing only where the trace header is wired - confirm with the user before reaching for it.
2026-07-24agents: target-debugger may escalate to etm-trace, prompt-gatedhathach
Instruction-level trace outranks PC-sampling when samples cannot resolve a mechanism, but the J-Trace is exclusive per-board hardware: the agent uses it only when its prompt says the board is trace-wired or the user asked, and otherwise proposes it in notes - mirroring the lock-force consent rule.
2026-07-24etm-trace: post-rename references, per-board hardware-consent gatehathach
target-debug replaced usb-target-debug in the debug-skill overhaul; update the cross-skill table and PC-sampling pointer. Add the consent gate: the J-Trace is a single probe moved between boards, so captures on a board the user did not just ask about need explicit confirmation that it is wired.
2026-07-24add etm-trace skill: unattended J-Trace ETM capture and analysishathach
Headless instruction-trace capture on any TRACE_ETM-capable board via Ozone's automation socket (port 19201, xvfb): etm_capture.py generates a throwaway project from the board's committed ozone reference (device, TIF, width, timing, hooks, JLinkScript inheritance), drives the session, and exports profile/coverage; etm_profile.py renders hot functions, coverage, per-line/instruction counters and ISR timing from the itrace stream. SKILL.md carries rig discipline, capture recipes, a new-board bring-up ladder and troubleshooting; boards.md is the per-board reference (config table + caveats) for all validated boards.
2026-07-24docs: address Codex/Copilot review on #3786hathach
- target-debug: fault frame lives on PSP when EXC_RETURN bit2 set (FreeRTOS tasks) — decode LR before choosing $msp/$psp (Codex; valid, our verify happened to fault on MSP) - esp-target-debug: show the Xtensa gdb for S3 in the attach recipe; clarify adapter serial = USB-SJ iSerial (colon MAC, hardware-verified) vs the CP2102N flasher uids in tinyusb.json (Codex; second half of the finding had the identifiers inverted) - esp plan: align serial form with the verified command; record the real console-gate outcome (UART0, USB-SJ console untested) (Copilot) - target-debug plan: Task 4 now consistently $JB/ARMv7-M matching the executed JLinkExe path (Copilot) - drop IDE-local .idea files swept in by the rename commit (Copilot)
2026-07-24docs(skills): tighten esp-target-debug/target-debug; agent routes backends ↵hathach
by board family - esp-target-debug: de-narrated (~1000 -> 847 words) — session-diary phrasing ('this unit', dates, 'we measured') replaced with durable reference facts; restructured per-board (P4 vs S3 notes); new Scripted-session gotchas section consolidates telnet-halt pattern, ESP_ONLYCPU, and ROM-frame guidance; UART-reset recipe stated once - target-debug: fix run-on seam from the -singlerun insertion - target-debugger agent: charter now resolves the board family FIRST and routes Espressif boards to esp-target-debug as primary playbook; skills table re-aligned - retrieval regression: 4/4 (agent routing, S3 keep-alive quirk, OpenOCD RTT on ST-Link, ROM-frame guidance)
2026-07-24docs(skills): esp-target-debug — Espressif built-in USB-JTAG backend, ↵hathach
rig-verified P4 (hand-wired USB-SJ breakout, GPIO24/25 from header J1): - COEXISTENCE verified: 303a:1001 + cafe:4008 enumerated simultaneously; gdb attach/halt/bt during live CDC traffic; symbolized app backtrace (tud_task_ext <- usb_device_task <- vPortTaskWrapper) - set ESP_RTOS FreeRTOS before board cfg -> full dual-core task list; without it, bare 'Remote target' - attach-may-reset nuance flagged (post-mortem autopsy caution) - console = UART0 (CP2102 flasher tty) on stock builds; D+/D- swap symptom documented (low-speed + error -71 vs full-speed) S3 (same-port PHY swap): - boundary captured live in dmesg: same hub port flips 303a:1001 -> cafe:4008 as the app boots; openocd 'esp_usb_jtag: could not find or open device!' verbatim - attach/halt/symbol resolution verified via board_test (usb_new_phy absent from ELF when CFG_TUD/TUH=0); app-context keep-alive quirk (~4 s unattended drop, -71 half-dead, UART esptool reset recovers); cpu1 OCD_ID=0 -> ESP_ONLYCPU=1; telnet-halt + gdb-read scripted pattern; RTC_CNTL PHY-mux reference (0x60008120) + esptool read_mem/write_mem - target-debug pointer + target-debugger agent table row
2026-07-24docs(target-debug): DWT data trace (verified both probe families); reorder ↵hathach
to table; SWO enable chain - DWT data trace: FUNCTION 0b0011 (ARMv7-M ARM Table C1-21) streams value + accessor-PC packets per access, no halt, no code. Verified on stm32f407disco (J-Link SWORead: 451 KB, value = uptime ms, PC = tusb_time_millis_api) and stm32h743nucleo (OpenOCD/ST-Link tpiu capture: 607 KB, same decode). Caveat recorded: R/W-only trace floods on polled variables. - SWO enable chain documented: tools own TRCENA/ITM/TPIU; vendor part bites — H7 needs DBGMCU trace clocks, PB3 manually muxed to AF0, native stlink-dap (hla tpiu silently no-ops), the cfg's stm32h7x.swo object (the .tpiu object is the parallel port), traceclk = c_ck 400 MHz (wrong guesses: ratio-garbage or silence). - Sections reordered to match the intrusiveness table (least->most intrusive); cross-references fixed; table gains the data-trace row.
2026-07-24docs(skills): formatting feedback — agent skill table, probe bullets, ↵hathach
aligned columns - target-debugger: skill list is now a table referencing skills by name only (path pattern stated once). - target-debug: probe-mapping run-on paragraph split into bullets; drop the GDB Ninth-Edition caveat (calibre now holds the Tenth-Edition PDF, id 2264). - Align markdown table columns across target-debug, usb-sniffer, usbmon, hil, usbtest and the agent (7 tables); tables with paragraph-length cells left unpadded (usbmon symptom map, usbtest case map).
2026-07-24docs(target-debug): vector catch, SWO trace, verifybin, FreeRTOS threads; ↵hathach
table integration - Vector catch + Cortex-M fault autopsy, verified with a deliberate bad-load on stm32f407disco: CFSR=0x8200 (BFARVALID|PRECISERR), BFAR = exact bad address, stacked pc addr2lined to the faulting line; gotchas recorded (stale FPB comparators fire phantom SIGTRAPs — scrub first; arm DEMCR after reset; loads precise / stores imprecise; ARMv6-M has no CFSR/BFAR) - SWO exception trace + hw PC sampling gate PASSED on F407: 680 KB of packets in 3 s (0x17 PC samples in flash range, 0x0E SysTick enter/exit); JLinkSWOViewerCL decodes stimulus only — raw SWORead is the recipe; SWOStart needs an explicit speed headless - verifybin 'Verify successful.'; FreeRTOS -rtos plugin lists all 6 cdc_msc_freertos tasks after a run->stop cycle (plain attach = 0xDEAD placeholder); semihosting anti-note; monitor-mode pointer (untested) - Intrusiveness table gains the new rows; agent playbook bullet updated; retrieval gate 5/5 with a fresh reader; executed plan committed
2026-07-24docs(target-debug): manuals, breakpoint/watchpoint arsenal, RTT via OpenOCDhathach
- Link J-Link UM08001, OpenOCD and GDB (Tenth Ed.) manuals - bp/wp depth with halt-per-hit cost model. Verified on stm32f407disco (J-Link) + raspberry_pi_pico (OpenOCD): FPB/DWT budget reads (M4 6 bp/4 wp, M0+ 4/2 exact), 'Hardware watchpoint' confirmation rule (software fallback single-steps = USB death), OpenOCD data-VALUE watchpoints, dprintf + breakpoint command lists exercised on hardware; JLinkGDBServer -singlerun lifecycle gotcha - RTT is not J-Link-only: OpenOCD rtt setup/start/server verified on pico (control block found at the nm address, LOG=2 boot banner captured over nc)
2026-07-24docs(skills): rename debug skills, drop the PC-host/TinyUSB-device assumptionhathach
Rename usb-target-debug -> target-debug, usb-debug -> usb-kernel-debug, usb-recover -> usb-kernel-recover (script filenames unchanged), and make all debug skills/agents decide tool applicability by which end of the link runs Linux: TinyUSB may run the device or host stack, and its peer may be a Linux PC, another TinyUSB board, or a Linux gadget (e.g. Raspberry Pi UDC). - usbmon: exists only when a Linux PC is the link's host - usb-kernel-debug: either Linux end; allowlist gains dwc3/libcomposite/udc_core for the gadget side of a Linux peer - usb-sniffer: the only full-visibility capture when TinyUSB is the host - target-debug: covers dcd_* and hcd_*/tuh_ debugging; channel choice by topology - update target-debugger/hil-operator agents, pre-pr, hil-validate.js, and the USB_RECOVER path constant in test/hil/usbtest.py - CLAUDE.md: fold the dcd/hcd datasheet cross-check rule into the read-doc line
2026-07-21docs: add read-doc skill, tighten CLAUDE.md and skill docs (#3778)Ha Thach
* docs: add read-doc skill for on-demand datasheet lookup Search and read MCU datasheets, reference manuals, errata, and the USB spec from a local Calibre library ($HOME/Documents/calibre-library) instead of answering register/bitfield/pinout questions from model memory. Gated on the library's existence, so it no-ops for contributors who don't have it. * docs: reference read-doc skill and tighten CLAUDE.md Point the datasheet/reference entry at the new read-doc skill, and trim sections that only duplicate a skill already owning the detail: PVS-Studio and Code Size collapse to pointers; GDB/Build/Flash command blocks condensed to essentials. 213 -> 129 lines; behavioral guidelines and the validation checklist unchanged. * docs: tighten skill redundancy; rename AGENTS.md refs to CLAUDE.md code-size: fold the step list into a sentence and drop invocation examples the argument tables already cover. hil: merge the duplicated self-lock bullets and compress the hifiphile note. usbmon: compress the group-membership setup paragraph. All commands, flags, lock rules, and report paths preserved. usb-target-debug and the pvs script only get stale AGENTS.md references renamed to CLAUDE.md (now the real file); run_pvs.sh no longer cites a --dump-files mention that CLAUDE.md dropped. * docs: fix review findings — restore Espressif cd step, ELF placeholder, code-size comment Codex/Copilot/Claude review of #3778: the condensed Espressif bullet lost its cd (idf.py resolves the project from CWD, so the command failed from repo root); the GDB example now uses the build/your_app.elf placeholder that docs/troubleshooting.rst established; the code-size invocation comment no longer references --combined, which the shown command doesn't use.
2026-07-18skill(usb-sniffer): make rig references generic, setup as a scripthathach
- Drop the dated/host-specific tap topology; confirm the cabling each session instead (the tap gets re-cabled often), and read the DUT link speed from sysfs to pick --speed. - Genericize the hub-upstream reset-visibility note. - Rewrite "one-time setup" as a copy-paste shell block (udev + binary + Wireshark extcap symlink), keeping only the firmware-command caution.
2026-07-17skill: add usb-sniffer — wire-level capture with the ataradov hardware taphathach
Fourth view in the USB debugging toolset (usbmon = host URBs, usb-debug = host reasoning, usb-target-debug = device firmware, usb-sniffer = what actually crossed D+/D-). Covers the ataradov/usb-sniffer analyzer: headless pcapng capture (--speed ls/fs/hs, --fold, --limit self-exit), Wireshark/tshark analysis recipes, and the wire realities that bite: downstream broadcast, sniffer self-capture noise, xHCI devnum != wire address, tap-point-dependent reset visibility (hub choreography anchors), FS-behind-HS-hub splits. Every recipe hardware-validated on the rig, including the capture-window floor (a 3 s window provably misses the enumeration ladder; 3M packets minimum). Two udev files with distinct audiences, not one: - examples/device/99-tinyusb-examples.rules (renamed from 99-tinyusb.rules): the user-facing rules the examples need — cafe VID access, hidraw, the ModemManager blacklist, a couple of board probes. getting_started.rst, the webusb_serial README and its source comment point here. - tools/88-tinyusb.rules: the HIL rig's private probe/analyzer allowlist, now with the sniffer (6666:6620 + blank FX2LP 04b4:8613). Installed on the rig only; the usb-sniffer skill references it.
2026-07-17agent: add target-debugger — device-side root-cause loop on the HIL righathach
Opus-tier agent charter for backgrounding a long hardware debug session: instrument -> build -> flash under one held board lock -> dual-side capture -> correlate -> refine, strictly one instance, skills as source of truth (usb-target-debug, usbmon, usb-debug, usb-sniffer, usb-recover, hil). The charter encodes what dogfooding established: - diagnosis standard: evidence must show the mechanism, or a fix must flip the ORIGINAL failing case on hardware; stop after two evidence-free cycles and hand back a partial diagnosis - lock cadence: hold for the whole session, release around hil_test.py runs (it self-locks per board) - revert semantics: "fix stays, probe goes, re-verify clean" — instrumentation reverted, candidate fix left uncommitted and re-verified on a clean build, pristine firmware reflashed before lock release Returns a machine-parseable diagnosis report including ruledOut[] — disproven hypotheses are deliverables. Spec roster updated (opus/xhigh, effort requested per agent() call).
2026-07-17skill: add usb-target-debug — device-side capture & debug on the HIL righathach
Completes the debugging toolset (usbmon = what the host exchanged, usb-debug = why the host acted, usb-sniffer = what crossed the wire): TU_LOG/RTT capture, per-probe GDB autopsy without reset, RAM ring-buffer event trace, J-Link DWT_PCSR PC-sampling, dual-side capture posture, and board-lock rig discipline. Includes the implementation plan it executes. Hard-won warnings baked in from real bring-up sessions: volatile ring buffers vs -Os dead-store elimination, RTT NO_BLOCK_SKIP post-mortem limits (no overwrite mode exists), DHCSR validity anchors for register snapshots, release-lock-before-hil_test, and that a marginal just-recabled link can fake a deterministic firmware bug. Also ignore .claude/worktrees/.
2026-07-15hil: add usb_recover hub-cycle action; drop MosChip skips, gate it as ↵hathach
incompatible The MosChip MCS9990 card is physically removed from the rig: delete its cases-11/25 SKIP workaround (and the now-orphaned SKIP accounting) from usbtest.py and refuse to run outright if a DUT ever sits behind one again. usb_recover.sh gains `hub-cycle <busport>`: uhubctl VBUS cycle of the port feeding the device, walking upstream (parent hub -> root port) until it re-enumerates. Verified on the rig: leaf-level recovery (13-4.4 usbtest device) and full walk to the root port on a dead branch. SKILL.md updated for the action and the two-Renesas topology (root-port ppps is real; leaf 1a40:0201 hubs fake their "ganged" switching). Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01WxUeX4Yn26KibfjvDg2pN9
2026-07-14dcd(ci_hs): stale overlay fix; run usbtest on lpcxpresso43s67hathach
- dcd_edpt_stall flushes the primed buffer (ENDPTFLUSH), but the aborted transfer's dQH overlay can be left ACTIVE with mid-transfer state; the next prime after clear-halt then resumes the stale overlay instead of loading the fresh qtd, so post-halt IN reads return mid-buffer data (usbtest case 13 'buf[32] = 56 (not 0)', with case 18 failing downstream of the same corruption in the full battery). qhd_start_xfer now clears overlay.active alongside overlay.halted before linking the new qtd. - test/hil(hfp): drop lpcxpresso43s67's device/usbtest skip - the historical first-case wedge no longer reproduces on this branch, and with the overlay fix the board runs 30/30 on its Fresco xHCI host (previously 28/30 with deterministic case 13/18 failures). mimxrt1064_evk (imxrt dcache path) 30/30 regression-clean. - docs(hil skill): document the external hifiphile rig - pool test/hil/hfp.json, SSH-reachable from htpc/ci with no outbound SSH, exercised by the CI hil-tinyusb (hfp.json) job; never run HIL against it during development unless the user explicitly asks. Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_017TQZrFfU3K4Y198aLsUpBC
2026-07-14Merge remote-tracking branch 'origin/master' into usbtesthathach
# Conflicts: # .claude/skills/hil/SKILL.md # test/hil/hil_test.py
2026-07-14test/hil: usbtest fleet enablement, shuffled scheduling, unique PIDshathach
Pool/config: - record real uids (ra8m1_ek), enable usbtest for espressif s3/p4, then park ra6m5_ek and ra8m1_ek in boards-skip (ra6m5's usbtest/MSC traffic can kill the uPD720201 host on its ROM firmware; ra8m1 USBHS bring-up pending); max32666/nrf54lm20 stay enabled - their MosChip flakiness never wedges - re-enable device/usbtest on HS boards (mimxrt1064, ch32v307) now that uPD720201 firmware 2.0.2.6 fixes the command-ring death; mimxrt1015 stays skipped - its HS battery killed the controller on both ROM and 2.0.2.6 firmware (board-specific); match the moved host-test bundles (f723 <-> rt1064); skip never-passing tests on the new nrf5340dk/nrf54lm20dk boards and the detached pico host bundle, each documented with a comment Host-controller quirk gating in usbtest.py (auto-skip, self-heals on a healthy xHCI): - MosChip MCS9990 EHCI: case 25 (int-OUT never scheduled, FRINDEX bug) and case 11 (unlinked reads complete short/EREMOTEIO) - Renesas uPD720201 xHCI: firmware-gated. The card must run firmware >= 2.0.2.6 (RAM-uploaded - it reverts to ROM on every power cycle): on older firmware the command ring dies under unlink stress (a Configure Endpoint command stops completing; the hub worker deadlocks holding the device lock; only a host power cycle recovers; three boards reproduced it). usbtest.py reads the FW version register (PCI config 0x6c) and refuses to run at all on older firmware - hil_test surfaces that as a failed test with the reason. On current firmware the full 30-case battery runs (validated FS+HS: metro_m4, f723, f723-DMA all 30/30). Scheduling (hil_test.py): - Shuffle each (board, variant)'s test order with a seeded RNG (HIL_SHUFFLE_SEED to replay) so usbtest batteries and flash churn spread across the timeline instead of convoying on one controller. - Per-controller usbtest + flash semaphores: HIL_USBTEST_PARALLEL (default 4) concurrent usbtest batteries and HIL_FLASH_PARALLEL (default 8) concurrent flashes per host controller. Profiled on uPD720201 firmware 2.0.2.6 across 8/1..12/8: wall time falls 22.2/14.3/12.5/10.8 min at usbtest width 1/2/3/4 and plateaus there; zero controller errors everywhere; first battery case failures (leaf-hub bandwidth stretch) appear at 12/8, and flash width 12 only amplifies flasher-hub contention flakes - so 8/4 is the optimum. A separate battery-window flash throttle was profiled and dropped. - Give every example a unique hardcoded USB PID (0x4001-0x4022, usbtest keeps 0x4010) instead of the PID_MAP interface bitmap: different examples now always re-enumerate back-to-back, even on boards whose CPU reset does not drop D+ (WCH CH58x), so the EXAMPLE_PID table and same-PID adjacency reordering in hil_test.py are gone; only the variant-boundary same-example repeat needs a swap. - Report matrix: stable columns with the metric-bearing tests pinned first (usbtest, cdc_msc_throughput, msc_file_explorer[_freertos]), the rest alphabetical. Fail fast: - enum wait budget 8 s on the first attempt, 4 s on retries; dfu waits are deadline-based so dfu-util's own runtime counts against the budget. A device-absent failure now costs ~3-5x a passing test (20-30 s) instead of 10-30x (47-150 s). - CI runs hil_test with --retry 1 and no in-run second pass: a broken fixture fails the job fast instead of holding the self-hosted runner for hours and blocking other PRs' HIL jobs. hil_test still writes the .skip sidecar, so a manual re-run attempt only retests what failed. Review fixes (multi-agent adversarial review of this commit): - tinyusb_win_usbser.inf: the PID rework moved five CDC examples onto even PIDs the INF's odd-only DeviceList never matched (legacy-Windows usbser binding) - appended 0x4006/4008/400a/4020/4022 to both lists. - usbtest example: USBTEST_TIER is now overridable and the descriptors and pumps are tier-conditional, so a board whose DCD cannot serve a tier lowers it instead of skipping the whole example - RA2A1 (RUSB2 with no isochronous pipe) builds at tier 3 via its BOARD_ define; the host battery follows the tier advertised in bcdDevice. Tier-4 output verified byte-identical after the refactor. - dynamic_configuration's second config derived USB_PID + 11 = 0x4018, colliding with net_lwip_webserver - now USB_PID + 0x0100, outside the per-example space. tools/check_example_pids.py (pre-commit hook) enforces PID uniqueness incl. derived and literal idProduct values. - usbtest.py firmware gate: matched by device ID (uPD720201/720202, both use the 0x6c FW register), and an unreadable version (setpci missing/denied) now refuses with its own message instead of masquerading as "firmware 0x00000000"; noted the gate is necessary but not sufficient (board-specific kills stay per-board skips). - hil_test: deadline waits use time.monotonic(); multiprocessing context pinned to fork (raw semaphores in Pool initargs); flash and usbtest permits unified into one fail-closed, exception-safe ctrl_permit (unknown controller takes every slot and logs a warning instead of silently borrowing slot 0); an all-skipped battery reports as skip, not "0/0" failure; slow-body polls (mtp, printer, disk read) go through a shared deadline-based wait_until so their bodies count against the enum budget; throughput's FS detection compares serials case-insensitively like every other walk; a missing MSC read-speed line now fails the host msc_file_explorer test instead of passing with an empty metric. Hardening: - fail fast (15 s) when a driver-registry sysfs write blocks: a wedged device otherwise turns every subsequent battery into an unkillable D-state writer and silently hangs the whole run - usb-recover skill: a VM reboot is not a reliable cure (MosChip hubs latch up across the PCIe reset); full host power cycle is Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01HeF2gZ1M7GWkz6Av4BpKPg
2026-07-13Fix max-effort review findings in lock protocol, workflows, and docshathach
Confirmed by a 10-finder / 28-verifier adversarial review pass: board_lock.py — the flock is now the sole authority: drop cmd_hold's pid-liveness pre-gate (a live hil_test.py pool worker's stale record no longer blocks a genuinely free board); cmd_release probes the flock and only signals a verified holder, refuses to kill hil_test.py holders (CI mid-test), handles PermissionError; the holder daemon truncates its lock records on SIGTERM and keeps the success pipe clear of fds 0-2 (closed-stdio hold used to leave an orphan holder while reporting failure); --config default resolves beside the script. hil_test.py — truncate the lock record on per-board release (pool workers outlive their flocks); warn instead of silently failing open when the lock dir is unusable; error out on -b names absent from the config (was a silent zero-test exit 0, readable as a green HIL run); drop an emptied board row in accumulate_report (variant boards left a blank ghost row). workflows — remove the stray positional arg that made the validate size stage exit 2 on every run; wrap JSON.parse(args) in all six scripts; factor pr-babysit's drifted reply recipe into postReplyRecipe and dedup refutation replies across cycles; validate args.pr and maxCycles; driver-review rejects an empty dimensions list; hil-validate drops a dead guard clause and retries diagnostics with -v -r 1. agents/docs — port-dev scopes git clang-format to its own files (concurrent workers reformatted each other in shared checkouts); hil-operator/hil skill wording matches actual fail-fast output; the implementation plan is now a DO-NOT-EXECUTE historical record (banner + checked boxes) so plan-executing agents cannot revert shipped files. Verified: lock storm 1-winner-in-10, stale-record hold, closed-stdio hold, dead-pid cleanup, CI-holder refusal, ghost-row 4-scenario merge, unknown-board exit 1, py_compile + check.sh on all six workflows, pre-commit clean. Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Upj4hta5TNoAbidqeC1zZ6
2026-07-10Fix review findings and add static-analyzer agenthathach
Review-fix batch (owner-confirmed) on the multi-agent harness: - board_lock: detach holder stdio so a captured `hold` cannot hang on the daemon's inherited pipe; probe locks by holder-pid liveness instead of a momentary flock, which could spuriously fail a concurrent acquirer (storm-tested: 1 winner in 10, 0/15 acquire failures under probe storm) - hil_test: locked board renders a visible board-locked fail row so the report matches the exit code; stale marker cleared on a real re-run - pr-babysit: autoPush now opt-in (default dry run); resolve recipe paginates reviewThreads; post-push resolve gets issue-comment fallback - validate: size stage honors non-default base via --base-branch; pvs stage delegated to the new agent - new static-analyzer agent (sonnet): PVS-Studio SAST+MISRA for one board, structured findings gated on files changed vs base Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Rn1AN5DsTdFhRwhugfgKZi
2026-07-09skills: usbtest/usb-debug/usb-recover docs, hil runner noteshathach
Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01HeF2gZ1M7GWkz6Av4BpKPg
2026-07-09feat: Claude Code multi-agent dev/test harness for TinyUSBhathach
Add worker agents (builder, port-dev, driver-reviewer, hil-operator, pr-monitor), deterministic workflows (validate, fanout-dev, driver-review, hil-validate, full-check, pr-babysit) and a /pre-pr gate skill, so sessions can fan build/test/review/PR-triage work out to tiered subagents. pr-babysit drives a PR to green: triage CI + bot reviews, fix validated findings, verify, push, and reply-to + resolve each inline review thread (fixed or refuted). Replace the stop-the-runner HIL discipline with per-board flock locks: test/hil/board_lock.py plus a fail-open guard in hil_test.py let CI and dev sessions share the rig per board (locked boards fail fast and re-run; HIL_NO_BOARD_LOCK=1 is a user-authorized bypass). The actions-runner is never stopped. Design spec, implementation plan, and real-rig smoke evidence under docs/superpowers/. Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Rn1AN5DsTdFhRwhugfgKZi
2026-06-30docs: convert changelog release notes from RST to Markdown (#3746)0.21.0Ha Thach
* docs: convert changelog release notes from RST to Markdown
2026-06-30make-release skill: tighten to commands + essential judgmenthathach
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-30docs: move changelog to docs/changelog, drop the docs/info folderhathach
Relocate docs/info/changelog/ -> docs/changelog/ (docs/info held only the changelog) and update all references: the toctree, README + MAINTAINERS links, make_release.py, and the make-release skill. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-30build.py: prefer pico/pico2 for rp2040 CI; skill: drop one-time 0.20.0 ↵hathach
backfill note - ci_preferred_boards: rp2040 -> raspberry_pi_pico, raspberry_pi_pico2 so the one-board CI/metrics build uses a Pico (the first-alphabetical board failed). - make-release skill: the metrics backfill was a one-time 0.20.0 task, not a recurring release step; keep only the CI auto-compare note. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-30make-release skill: document code-size compare vs previous releasehathach
CI auto-uploads metrics.json + a compare to each release on the release event (needs the previous release's metrics.json); plus the procedure to backfill a missing baseline by building the old tag's own tree and post-processing its linker maps (current tooling can't build old source — co-evolved tree). Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-30Fix code-review findings (changelog rendering, release skill, sidebar)hathach
- changelog: fix 3 silent RST mis-renders carried over from the old monolith — Markdown link in 0.7.0, mismatched/single backticks in 0.18.0 / 0.20.0 - make-release skill contributors one-liner: parallelize the gh fetch, anchor the bot filter (was a substring that dropped handles like "abbott"), and join with ", " (paste -sd cycles the delimiter -> "@a,@b @c"); finalize now stages only the reviewed set (git add -A -- ':!.idea'); drop the obsolete CRLF gotcha - make_release.py: emit LF not CRLF in the repository.yml insertion (fixes the gotcha at the source) - docs sidebar: drop the hardcoded furo component list; override brand.html to include furo's own template + the sponsor button (decoupled from furo internals, no upper-bound pin needed); move sponsor styles into custom.css - .pre-commit-config.yaml: drop stale end-of-file-fixer excludes for the deleted contributors/CoC include shims Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-30Address Codex review: release skill + furo requirementhathach
- make-release skill: stage new files with git add -A in finalize, use unprefixed release tags (X.Y.Z), and run validate build steps in subshells so the cwd doesn't leak between commands - docs/requirements.txt: require furo>=2025.12.19 so the sidebar component list in conf.py (incl. variant-selector.html) is always available Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-30Address Copilot review; move release process into the make-release skillhathach
- README: restore the separate CH32V103 / CH583,CH582 rows in the Supported CPUs table — the merged row wrongly applied "ISO data loss [2]" to CH583/2 - Fix typos in historical changelog entries (santiy, Venndor, dynamnic, bagde, masstorage, techinical, walkaround, "Update Update") flagged by Copilot - Replace the AGENTS.md Release section with a pointer to the make-release skill; add a Finalize step (maintainer commit/tag/push + GitHub release) to the skill so nothing is lost Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-29Bump version to 0.21.0; rework changelog, contributors, and docshathach
Release: - Bump version to 0.21.0 and regenerate tusb_option.h, library.json, repository.yml, sonar-project.properties, boards.rst, dependencies.rst - Add 0.21.0 release notes and split the changelog into per-release files under docs/info/changelog/ (date out of title, driver/class groups as sub-headings, DCD & HCD section after Device/Host stacks) Contributors: - Credit each release's PR authors in a Contributors section - Drop the curated contributors page; add MAINTAINERS.rst Docs: - Update Code of Conduct to Contributor Covenant 3.0 (keep it in the repo, remove it from the built docs) - Sidebar: add a home entry, rename the group to "Documentation", move Changelog into it, add a GitHub Sponsor button, merge external links, rename FAQ; hide the inline toctree on the landing page - Add the make-release skill and update the AGENTS.md release process Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-29docs: address Copilot review on the example READMEshathach
- Order CFG_TUH_DEVICE_MAX before CFG_TUH_HID in the host config snippets (cdc_msc_hid, hid_controller) so the documented snippet has no forward macro reference when copied into tusb_config.h. - Fix stale `examples.rst` references: the generator now writes per-group `docs/examples/<group>/index.rst` pages, so update the conf.py comment and the build-doc SKILL.md accordingly. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-29docs: add build-doc tooling and a README for every examplehathach
Documentation tooling: - Add the `build-doc` skill and `tools/build_doc.py` wrapper for local Sphinx builds (clean / -W / open). - Enable Markdown (MyST) in conf.py and auto-collect examples/{device,host,dual}/*/README.md into a 3-level Examples nav (Examples > Device/Host/Dual > example), noting each page's source location and normalizing headings to a single H1. - Remove the stale `.claude/commands/build-doc.md`; point the AGENTS.md Documentation section at the skill. Example docs: - Add a README.md for every device/host/dual example: what it does, USB interface table, notable tusb_config.h settings, generic CMake + Make build steps, and how to try it. - Fold each *_freertos variant into its base README, noting the FreeRTOS source path and any RTOS-specific behavior. Generated docs/examples/ output is git-ignored. Builds clean with `sphinx-build -W`. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-24docs: add usbmon skill for capturing/debugging USB bus traffichathach
Adds a Claude Code skill that wraps usbmon + tshark to capture host-side URBs into a Wireshark pcapng and decode them, for debugging TinyUSB device enumeration/transfer issues on real Linux hardware. Includes a usbcap.sh capture helper (bus / VID:PID / auto) plus filter, errno, and symptom->check reference tables. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-11pvs skill: harden credentials parsing; note compile DB is exported by defaultClaude
- Parse PVS_STUDIO_CREDENTIALS into two quoted fields (no glob/word-split). - AGENTS.md: examples build sets CMAKE_EXPORT_COMPILE_COMMANDS ON already. Addresses Copilot review on #3695.
2026-06-11pvs skill: mirror CI --security-related-issues flag and ignore SARIF outputClaude
- Add --security-related-issues to run_pvs.sh and AGENTS.md analyze commands so local runs reproduce the CI SAST classification (static_analysis.yml). - Ignore *.sarif so a successful run leaves the worktree clean. Addresses Codex review on #3695.
2026-06-05Compact pvs skill; fix PVS-Studio -S/--dump-files docs in AGENTS.mdClaude
The AGENTS.md '-S src/foo.c' example was inaccurate: -S takes a plaintext file listing source paths, not paths directly. Drop --dump-files from the documented commands (it scatters .PVS-Studio.i/.cfg dumps across the tree; FP-debugging only) and reference the new pvs skill. https://claude.ai/code/session_015inWmFhRYSq17CxMukdoqX
2026-06-05Add pvs skill to run PVS-Studio analysis for a boardClaude
Bundle a run_pvs.sh helper (takes BOARD as its first argument) that follows the PVS-Studio static-analysis flow from AGENTS.md: build all examples with an exported compile_commands.json, run pvs-studio-analyzer against .PVS-Studio/.pvsconfig, then emit errorfile + SARIF reports. https://claude.ai/code/session_015inWmFhRYSq17CxMukdoqX
2026-06-02ci: address second codex/copilot review roundhathach
- claude.yml: drop the issues "assigned" trigger; its author_association gate keys on the issue author, not the assigner, so a maintainer assigning an outside contributor's issue would be wrongly skipped. - claude-code-review.yml: issues: read -> write so use_sticky_comment can create/update its PR comment via the issues API. - hil SKILL.md: make local/remote command blocks copy-pasteable (drop [-b BOARD_NAME] notation for concrete examples) and fix timeout (600000 ms is 10 min; use 1200000 ms for the stated 20 min). Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-02ci: address codex/copilot review on claude workflowshathach
- claude.yml: gate @claude on author_association (OWNER/MEMBER/COLLABORATOR) so the write-scoped token and OAuth secret are never issued for an untrusted commenter on this public repo (defense-in-depth). - claude-code-review.yml: skip fork PRs in the job condition (head.repo.full_name == github.repository) since forks get no secrets and would only fail noisily; fix the misleading token comment; pass additional_permissions: actions: read so actions: read is effective. - hil SKILL.md: reword hostname guidance, use full test/hil/* paths, and show an explicit CONFIG= assignment so the local command is runnable. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>