<feed xmlns='http://www.w3.org/2005/Atom'>
<title>tinyusb.git/.claude, 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/.claude?h=claude%2Fusbh-enum-timeout</id>
<link rel='self' href='http://cgit.235523.xyz/tinyusb.git/atom/.claude?h=claude%2Fusbh-enum-timeout'/>
<link rel='alternate' type='text/html' href='http://cgit.235523.xyz/tinyusb.git/'/>
<updated>2026-08-27T05:21:04Z</updated>
<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>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>
<entry>
<title>README sponsor list and triage labels (#3842)</title>
<updated>2026-08-25T03:50:36Z</updated>
<author>
<name>Ha Thach</name>
<email>thach@tinyusb.org</email>
</author>
<published>2026-08-25T03:50:36Z</published>
<link rel='alternate' type='text/html' href='http://cgit.235523.xyz/tinyusb.git/commit/?id=60194f8d10ebc9ec1aeba559e359ebe3ca9b756b'/>
<id>urn:sha1:60194f8d10ebc9ec1aeba559e359ebe3ca9b756b</id>
<content type='text'>
</content>
</entry>
<entry>
<title>ci: scope the build matrix and the HIL run to what a PR affects</title>
<updated>2026-08-21T04:07:27Z</updated>
<author>
<name>hathach</name>
<email>thach@tinyusb.org</email>
</author>
<published>2026-08-21T04:07:27Z</published>
<link rel='alternate' type='text/html' href='http://cgit.235523.xyz/tinyusb.git/commit/?id=04d0f71984117b8c72349f4584bd9e26a37b129c'/>
<id>urn:sha1:04d0f71984117b8c72349f4584bd9e26a37b129c</id>
<content type='text'>
Every PR built all 74 legs (2494 example builds on GHA cmake alone) and flashed
all 30 rig boards, whatever it touched. One classifier now walks the PR diff twice
and answers three questions: which families to build, which examples per family,
and which boards run which tests. Fail-open throughout - anything no rule
classifies, any exception, any unusable output falls back to the full matrix, and
a master push always builds everything.

test/hil/helper/hil_select.py moves to tools/ci_select.py: it is no longer HIL-only,
and tools/ is where the build side can import it. test_hil_select.py follows it as
test_ci_select.py.

Rules (docs/superpowers/specs/2026-08-19-ci-build-family-filter-design.md holds the
full table): a port selects the families whose family.cmake references it, and its
role - a dcd change skips host examples and vice versa; a class selects only the
examples whose tusb_config.h enables its CFG_TU[DH]_ macro, following cross-class
includes; an example selects itself; hw/bsp selects its family or board; hw/mcu and
lib select whoever references them. CMake is the reference for all of it - make
follows whatever cmake decides, family.mk is never scanned.

Empty means empty (maintainer ruling): a rule that classifies a path to nothing
selects nothing. Ports no family references, classes no config enables, libs no
example builds and hw/mcu paths that resolve nowhere are all real - nothing
compiles them, so nothing can validate them, and the master-push build is the net.
Structural tests pin each such case with an explicit allowlist, so the day one
stops being empty it fails pre-commit instead of silently narrowing CI.

Per-example builds: build.py grows a repeatable -e, resolved against the targets
CMake actually registered and batched into one `cmake --build --target a b c`.
build_utils mirrors CMake's family_filter (the whole FAMILY_MCUS list, ${...} and
string(TOUPPER ...) resolved) for the cmake side, while the make side keeps
master's algorithm verbatim - the two build systems answer differently and a shared
answer breaks lpc54's make link. hil-build gains this even on a full selection:
1702 example builds become 515.

Transport: the selection travels as a file, never an argv or env var - a mass-sweep
diff selects 261 KB against a 128 KiB exec limit, and E2BIG would fail the step
before its own fallback could run. CircleCI carries the example map inside the
generated config (pipeline parameters cap at 512 chars), swapped into the parameter
defaults by sentinel match, and drops the scoping wholesale if that rewrite fails.
Every PR-derived value written to $GITHUB_ENV/$GITHUB_OUTPUT is character-screened.

Code metrics follow the scoping: metrics.py emits per-example totals, and
metrics_pair_compare compares the (board, example) pairs present on both sides
instead of a scoped run against a full-matrix average.

The selector's own suite gates it in both providers: a selector that exits 0 with
valid-but-wrong JSON is the one failure fail-open cannot catch, so a red suite
means the full matrix.
</content>
</entry>
<entry>
<title>docs: add hardware-in-the-loop rig reference</title>
<updated>2026-08-20T17:47:27Z</updated>
<author>
<name>hathach</name>
<email>thach@tinyusb.org</email>
</author>
<published>2026-08-20T07:30:59Z</published>
<link rel='alternate' type='text/html' href='http://cgit.235523.xyz/tinyusb.git/commit/?id=872b4fbdc3c607b522211839a6b3b82e18310a1b'/>
<id>urn:sha1:872b4fbdc3c607b522211839a6b3b82e18310a1b</id>
<content type='text'>
Document the ci and hfp HIL rigs in enough detail to reproduce one: bill of
materials with photos, BIOS/IOMMU and vfio-pci passthrough on the Proxmox
host, the Renesas uPD720201 firmware install, the guest software and
permissions, the one-hub-per-root-port USB topology rule and the per-box
split of probe and DUT hubs, how CI drives the rigs, and the operational
gotchas.

The attached-board table is generated from test/hil/tinyusb.json and
test/hil/hfp.json by tools/gen_doc.py into docs/reference/hil_boards.md,
which the page includes. Sphinx excludes that partial so it is not also
built as an orphan document.

Also exclude docs/superpowers/ from the Sphinx build: it holds internal
plans, specs and handoffs rather than published documentation, and since
nothing references them from a toctree each emitted "document isn't
included in any toctree" -- 26 warnings in total, so build_doc.py -W could
never pass. It now does.
</content>
</entry>
<entry>
<title>hil: address Copilot review — loud extraction markers, exit-visible variant warnings</title>
<updated>2026-08-20T11:30:45Z</updated>
<author>
<name>hathach</name>
<email>thach@tinyusb.org</email>
</author>
<published>2026-08-20T11:30:45Z</published>
<link rel='alternate' type='text/html' href='http://cgit.235523.xyz/tinyusb.git/commit/?id=0fa0ece024fecae0847459b5949c66f40fcc6e11'/>
<id>urn:sha1:0fa0ece024fecae0847459b5949c66f40fcc6e11</id>
<content type='text'>
The workflow-logic harness slices hil-validate.js between marker strings (the body is not
a module; the runtime wraps it, so markers are the only handle). A renamed marker used to
produce a garbage slice and a confusing ReferenceError; it now fails naming the missing
marker, proven by mutating the marker and watching the message.

The variant-warning loop in hil_ci.sh read variant_names through a process substitution --
the exact exit-status blindness the comment in resolve_build_dirs warns about, two
functions earlier in the same file. A plain command-substitution assignment is visible to
set -e, so a malformed roster now aborts instead of silently skipping the warnings.
</content>
</entry>
<entry>
<title>hil, docs: reference toolchains by their official env vars, not one rig's paths</title>
<updated>2026-08-20T10:43:44Z</updated>
<author>
<name>hathach</name>
<email>thach@tinyusb.org</email>
</author>
<published>2026-08-20T10:43:44Z</published>
<link rel='alternate' type='text/html' href='http://cgit.235523.xyz/tinyusb.git/commit/?id=21d7332d5884e0abbf9e3f3762deefa589564783'/>
<id>urn:sha1:21d7332d5884e0abbf9e3f3762deefa589564783</id>
<content type='text'>
~/code/pico/pico-sdk and $HOME/code/esp-idf/export.sh are the ci rig's private layout;
written into instructions they silently stop being true on tusb, a dev PC, or any
future rig. The docs now use the variables the vendors define -- PICO_SDK_PATH for the
Pico SDK and IDF_PATH for ESP-IDF, activated explicitly as `. "$IDF_PATH/export.sh"` --
and leave where the checkouts live to each host's profile.

The variables are only useful if the shells that agents actually get can see them, and
`ssh &lt;rig&gt; 'cmd'` is non-interactive AND non-login: it reads no profile, and Debian's
sshd-sourced ~/.bashrc returns at the interactive guard before most of the file. The ci
rig already keeps its exports in the section ABOVE that early-return; IDF_PATH now sits
there beside PICO_SDK_PATH, and the whole chain is verified from a plain non-interactive
ssh: both variables visible, `. "$IDF_PATH/export.sh"` activates ESP-IDF v5.5.3 with
idf.py on PATH -- no login shell, no alias, no hard-coded path. hil-pool-check documents
that placement so the next rig is set up the same way.
</content>
</entry>
<entry>
<title>skills, CLAUDE.md: correct instruction claims the source refutes</title>
<updated>2026-08-20T09:47:22Z</updated>
<author>
<name>hathach</name>
<email>thach@tinyusb.org</email>
</author>
<published>2026-08-20T09:47:22Z</published>
<link rel='alternate' type='text/html' href='http://cgit.235523.xyz/tinyusb.git/commit/?id=126e29f777f07a35b06b327b50e62e0150521b48'/>
<id>urn:sha1:126e29f777f07a35b06b327b50e62e0150521b48</id>
<content type='text'>
Findings from an audit of the .claude instruction surface: 1,387 falsifiable claims
extracted with a quote-gate (zero hallucinated), each verdicted against the code, the
kernel at the rig's running version, or the rig itself. Only claims the current source
actively refutes were touched; hard-earned rig knowledge stands as source of truth.

usbtest told operators to stop the actions runner before touching hardware. Every
other file forbids exactly that since the per-board flock landed - following it stops
CI on a shared rig. Twice in the same file it said hil_test.py serializes usbtest
batteries; hil_lock.py budgets 2 concurrent per host controller, a profiled
throughput trade rather than a safety ceiling - while the recorded hazards stay: an
unbudgeted battery has hard-frozen the rig through a VFIO xHCI PCIe error, and a
marginal DUT port bouncing under concurrent batteries has killed a uPD720201 outright,
which lowering the widths does not fix. It also cited src/usb_descriptors.h and
src/tusb_config.h as if repo-relative (they are the example's own, and the comment sat
above the cd that establishes the base) and presented usbtest_do_ioctl() and
tools/usb/testusb.c as repo files when both are Linux kernel.

usb-kernel-recover called the Renesas ppps "real per-port" in its rig layout while
saying four sections earlier that VBUS stays up. Both describe the same silicon and
only the second was right: owner-confirmed, the cards advertise ppps and do not
implement it, so a root cycle is purely a re-enumeration - both places now say so and
warn against reading uhubctl's flag as power control. The layout listed three cards;
the rig has five (01/03/04/05/06:00.0; AMD 02:00.0 has none), re-derived from
lspci/uhubctl/sysfs and written as a derivation recipe because bus numbers renumber
every boot. The root-cycle rung also gains the board-flock requirement the other
files already demand - it avoids the KERNEL device_lock, which is a different lock,
and the text now names the two apart instead of reading as "no reservation needed".

CLAUDE.md listed src/tusb_config.h among the key files; no such path exists -
tusb_config.h is per-example, src/tusb_option.h is the file that lives there.
</content>
</entry>
</feed>
