<feed xmlns='http://www.w3.org/2005/Atom'>
<title>tinyusb.git, branch claude/usbh-enum-timeout</title>
<subtitle>Unnamed repository; edit this file 'description' to name the repository.</subtitle>
<id>http://cgit.235523.xyz/tinyusb.git/atom/?h=claude%2Fusbh-enum-timeout</id>
<link rel='self' href='http://cgit.235523.xyz/tinyusb.git/atom/?h=claude%2Fusbh-enum-timeout'/>
<link rel='alternate' type='text/html' href='http://cgit.235523.xyz/tinyusb.git/'/>
<updated>2026-08-27T17:36:38Z</updated>
<entry>
<title>usbh: add enumeration control transfer timeout</title>
<updated>2026-08-27T17:36:38Z</updated>
<author>
<name>hathach</name>
<email>thach@tinyusb.org</email>
</author>
<published>2026-08-27T17:36:38Z</published>
<link rel='alternate' type='text/html' href='http://cgit.235523.xyz/tinyusb.git/commit/?id=f748c01c4fa1104168a0f3317c37e6586d0027f7'/>
<id>urn:sha1:f748c01c4fa1104168a0f3317c37e6586d0027f7</id>
<content type='text'>
A device that ACKs SETUP but never completes the following stage (e.g. NAKs
the EP0 IN data stage forever) froze the control state machine: enumeration
never finishes and hub interrupt polling never resumes, so one dead device
blocks all further enumeration on the bus. Observed with a degraded USB disk
behind a hub on a rp2040 PIO-USB host: wire capture shows SETUP ACKed then
an endless IN/NAK storm with no completion event.

Arm a watchdog (CFG_TUH_ENUM_TIMEOUT_MS, default 5s to match Linux's
USB_CTRL_GET_TIMEOUT, 0 disables) on enumeration-owned control transfers
using the existing call_after slot, which already wakes a blocked host task.
On expiry abort the transfer at hcd level and complete it as FAILED so the
normal enumeration failure path frees dev0 and resumes hub polling.
Non-enumeration control transfers keep their current behavior.
</content>
</entry>
<entry>
<title>Merge pull request #3856 from hathach/claude/hil-drop-nt</title>
<updated>2026-08-27T08:09:49Z</updated>
<author>
<name>Ha Thach</name>
<email>thach@tinyusb.org</email>
</author>
<published>2026-08-27T08:09:49Z</published>
<link rel='alternate' type='text/html' href='http://cgit.235523.xyz/tinyusb.git/commit/?id=42db982e7c6e8ee7d2f80d15a93a7092d3b708c9'/>
<id>urn:sha1:42db982e7c6e8ee7d2f80d15a93a7092d3b708c9</id>
<content type='text'>
test/hil: drop the Windows accommodations, which accommodate nothing</content>
</entry>
<entry>
<title>Merge pull request #3855 from hathach/claude/pr-babysit-split-triage</title>
<updated>2026-08-27T07:56:23Z</updated>
<author>
<name>Ha Thach</name>
<email>thach@tinyusb.org</email>
</author>
<published>2026-08-27T07:56:23Z</published>
<link rel='alternate' type='text/html' href='http://cgit.235523.xyz/tinyusb.git/commit/?id=677182694f555c451eaec0a0d4ee7b14ac532783'/>
<id>urn:sha1:677182694f555c451eaec0a0d4ee7b14ac532783</id>
<content type='text'>
workflows/agents: overlap pr-babysit's review and CI lanes; split pr-monitor; pin agent efforts</content>
</entry>
<entry>
<title>validate: add claude + codex diff-review stages (opus/high, sol/high)</title>
<updated>2026-08-27T05:21:04Z</updated>
<author>
<name>hathach</name>
<email>thach@tinyusb.org</email>
</author>
<published>2026-08-27T05:21:04Z</published>
<link rel='alternate' type='text/html' href='http://cgit.235523.xyz/tinyusb.git/commit/?id=92b38fc3b5e9080c96294079e6117d74429f3448'/>
<id>urn:sha1:92b38fc3b5e9080c96294079e6117d74429f3448</id>
<content type='text'>
The claude stage reviews the diff directly (the code-review skill is a CLI
built-in, unavailable to subagents); the gate is enforced in-script from
structured findings, failing only on confirmed correctness/safety bugs.
</content>
</entry>
<entry>
<title>pr-babysit: overlap a fast review lane with the CI watch</title>
<updated>2026-08-27T05:21:04Z</updated>
<author>
<name>hathach</name>
<email>thach@tinyusb.org</email>
</author>
<published>2026-08-27T05:21:04Z</published>
<link rel='alternate' type='text/html' href='http://cgit.235523.xyz/tinyusb.git/commit/?id=208f82efe8b9dc7ca3eb210dcbf455a14c97cf3c'/>
<id>urn:sha1:208f82efe8b9dc7ca3eb210dcbf455a14c97cf3c</id>
<content type='text'>
Review findings are validated, fixed, and pushed without waiting on CI;
checkoutDir decouples the PR checkout from the session cwd. File-less CI
failures are scoped by a dedicated agent, paths canonicalized and
existence-checked via git ls-files, overlapping groups merged. Per-id
reply/resolve accounting retries failures and holds the green exit until
all outward work is drained.
</content>
</entry>
<entry>
<title>agents: split pr-monitor into pr-ci-watcher + pr-review-validator; rename port-dev/driver-reviewer to code-writer/code-verifier; pin model+effort on every agent</title>
<updated>2026-08-27T05:21:04Z</updated>
<author>
<name>hathach</name>
<email>thach@tinyusb.org</email>
</author>
<published>2026-08-27T05:21:04Z</published>
<link rel='alternate' type='text/html' href='http://cgit.235523.xyz/tinyusb.git/commit/?id=2b9ddd8b00eb57225fd9caeecd0da1a7954aee06'/>
<id>urn:sha1:2b9ddd8b00eb57225fd9caeecd0da1a7954aee06</id>
<content type='text'>
</content>
</entry>
<entry>
<title>test/hil: drop the Windows accommodations, which accommodate nothing</title>
<updated>2026-08-27T01:54:07Z</updated>
<author>
<name>hathach</name>
<email>thach@tinyusb.org</email>
</author>
<published>2026-08-26T18:01:30Z</published>
<link rel='alternate' type='text/html' href='http://cgit.235523.xyz/tinyusb.git/commit/?id=9baa97a8c6cc671aefe26168b3d8281da070ebf9'/>
<id>urn:sha1:9baa97a8c6cc671aefe26168b3d8281da070ebf9</id>
<content type='text'>
hil_test.py cannot run on Windows and never could: it imports helper.hil_lock,
whose module-level `import fcntl` is POSIX-only, so the harness fails at import
before a line of it executes. Past that it reads /sys/bus/usb, /dev/bus/usb,
/dev/serial/by-id and /proc, kills by process group, and takes flock board
locks -- none of which Windows has.

So the guards were protecting a platform the code cannot reach:

- run_cmd branched three ways on os.name to decide whether to set
  start_new_session and whether to killpg. The non-POSIX arm called p.kill()
  instead, which kills only the direct child -- exactly the semantics the whole
  containment design rejects, since a flasher run through a shell reparents out
  of reach. Dead code that documented the wrong answer.
- hil_test picked multiprocessing's default context on Windows "so it still
  IMPORTS there". It does not import there.
- test_device_audio_test_freertos returned 'skipped' on nt before touching
  ALSA, in a function only ever reached from a worker that cannot start there.
- Seven @unittest.skipIf(os.name == 'nt') decorators across the two suites.
  These were the only ones with a real effect -- the unit tests DO import and
  run on Windows, because they stub pyserial and mostly exercise pure logic --
  but what they buy is a partially-green suite for a harness that cannot run,
  and nothing verifies the set is correct: the hil-test hook only ever runs on
  ubuntu-latest, so a missing guard fails silently until someone tries.

Removing them makes the POSIX assumption single and explicit rather than
scattered and half-honoured. Nothing changes on Linux: every removed branch was
the one already taken there.

Removing the run_cmd guards also removes their `else: p.kill()` arms. Those were
the Windows branches, and p.kill() reaches only the direct child -- a flasher run
through a shell keeps grandchildren it cannot touch, which is the semantics this
containment design rejects. RunCmdCleanupShape pins what is left: both cleanup
paths killpg, no try carries an else whose body would run when the kill
SUCCEEDED, and the BaseException path still re-raises. Structural rather than
behavioural because driving a real SIGINT into a blocked communicate() is
timing-dependent, and what actually breaks this block is an edit that rebinds a
branch -- which is a shape.
</content>
</entry>
<entry>
<title>test/hil: run the HID echo in a child, which is the only bound that works (#3852)</title>
<updated>2026-08-27T01:43:02Z</updated>
<author>
<name>Ha Thach</name>
<email>thach@tinyusb.org</email>
</author>
<published>2026-08-27T01:43:02Z</published>
<link rel='alternate' type='text/html' href='http://cgit.235523.xyz/tinyusb.git/commit/?id=d799b6f572e4b39ebebcf72126d3120f7829c034'/>
<id>urn:sha1:d799b6f572e4b39ebebcf72126d3120f7829c034</id>
<content type='text'>
hid_generic_inout was the last unbounded blocking IO in the file. hidapi's
hidraw backend reads manufacturer/product via udev for each device reaching
create_device_info_for_device, both usb_string_attr served under the device
lock a wedged usbfs ioctl holds — and every DUT here is VID cafe, so a wedged
sibling stalls the walk.

A thread cannot bound it: cython-hidapi calls hid_open and hid_close bare
(0.15.0 hid.pyx), so they hold the GIL and the waiter can never resume.
Measured — a 1.0s bound never returned. run_cmd's killpg reaches a child
regardless; it gains an argv form for the -c body.

Filters on both ids: hidapi only runs the free uevent pre-check when ids are
passed (linux/hid.c:962), so an unfiltered walk sends every device straight to
the locked reads. Tests stall via ctypes.PyDLL, which unlike CDLL holds the
GIL — the shape a thread bound cannot cover.</content>
</entry>
<entry>
<title>test/hil: make main() readable and stop the suite sleeping (#3848)</title>
<updated>2026-08-26T06:41:05Z</updated>
<author>
<name>Ha Thach</name>
<email>thach@tinyusb.org</email>
</author>
<published>2026-08-26T06:41:05Z</published>
<link rel='alternate' type='text/html' href='http://cgit.235523.xyz/tinyusb.git/commit/?id=b15c720ab0a36ee16c1cf7984c7c0f4ccf3a7015'/>
<id>urn:sha1:b15c720ab0a36ee16c1cf7984c7c0f4ccf3a7015</id>
<content type='text'>
Three readability changes with no behaviour change on the healthy path —
every pre-existing test passes untouched.

main() was 368 lines with try/finally three deep, its two abort paths
near-identical 40-line blocks; _abort_report holds that shape once, and the
controller-hint cache and pool construction move to their own helpers.
368 -&gt; 279, test_board 180 -&gt; 151, test_device_usbtest 164 -&gt; 125.

test_hil_bounded.py cost 78s on every commit under test/hil/, mostly one 3s
post-flash settle paid by ten tests against a fake rig. Now 37s.

Fixes two pre-existing defects the extraction exposed: _write_failed_spec was
unguarded inside the abort path, so an OSError there replaced the caller's
RuntimeError and no report was written at all; _save_controller_hints overlaid
a startup snapshot onto the re-read cache, clobbering a concurrent job's newer
values. Also five comments that stated the opposite of the code, and both table
renderers measuring width with len() against two-column status marks.</content>
</entry>
<entry>
<title>hil: make hil_report.md a rendering of hil_report.json (#3840)</title>
<updated>2026-08-25T08:04:42Z</updated>
<author>
<name>Ha Thach</name>
<email>thach@tinyusb.org</email>
</author>
<published>2026-08-25T08:04:42Z</published>
<link rel='alternate' type='text/html' href='http://cgit.235523.xyz/tinyusb.git/commit/?id=375e20090a0a60fd2d47ba6553d189e05482dfea'/>
<id>urn:sha1:375e20090a0a60fd2d47ba6553d189e05482dfea</id>
<content type='text'>
hil_report.json and hil_report.md were written independently. Four writers
produced the markdown and three wrote no JSON at all -- and those three are the
paths where a run died, so a JSON consumer saw nothing exactly when it mattered:
the per-board verdicts an agent hands back reported the whole fleet as "no
report row" while a human read the real story from the markdown.

Every writer now goes through render_report(), so a table can never contain
something the JSON does not. The document gains `scope` (a three-board PR run
and a full run that lost 24 boards were indistinguishable) and `caveat` (how the
run ended). `banner` carries rig health across an --accumulate retry; `caveat`
records how a run ended and must not -- conflating them made a clean retry
publish an abandonment that never happened.

helper/hil_report.py owns the document end to end, dissolving the import cycle
that forced write_timeout_report to compose its own markdown and removing a
duplicate cell classifier kept in sync by hand. hil_summary.py is deleted; its
CLI moves there. hil_ci.sh uploads the sidecar so a remote --accumulate has a
merge bas</content>
</entry>
</feed>
