<feed xmlns='http://www.w3.org/2005/Atom'>
<title>tinyusb.git/CLAUDE.md, branch merge_os</title>
<subtitle>Unnamed repository; edit this file 'description' to name the repository.</subtitle>
<id>http://cgit.235523.xyz/tinyusb.git/atom/CLAUDE.md?h=merge_os</id>
<link rel='self' href='http://cgit.235523.xyz/tinyusb.git/atom/CLAUDE.md?h=merge_os'/>
<link rel='alternate' type='text/html' href='http://cgit.235523.xyz/tinyusb.git/'/>
<updated>2026-08-18T09:58:58Z</updated>
<entry>
<title>skill(read-doc): search the Calibre database instead of the filesystem</title>
<updated>2026-08-18T09:58:58Z</updated>
<author>
<name>hathach</name>
<email>thach@tinyusb.org</email>
</author>
<published>2026-08-18T08:28:58Z</published>
<link rel='alternate' type='text/html' href='http://cgit.235523.xyz/tinyusb.git/commit/?id=f59c8948729debc6d57c4dfade5486176468edbf'/>
<id>urn:sha1:f59c8948729debc6d57c4dfade5486176468edbf</id>
<content type='text'>
Finding documents by walking the library tree misses anything the filename
does not carry - Calibre stores only a truncated title and the author there, so
the tags, series, publisher and description that hold most part numbers and
errata IDs are invisible to it. A zero-result tree search then reads as "the
document does not exist" rather than as a bad search; that happened here, and
led to a confident claim that a fully populated 14,000-file library was empty.

search.py queries metadata.db, ANDs its keywords across every metadata field
(including the stored filename), and prints the best matches first with the
exact path to read. Matching is NFKC + casefold, so a typed ASCII apostrophe or
mu reaches the titles that store the typographic ones.

Every printed path is checked on disk. Calibre renames &lt;author&gt;/&lt;title&gt; (&lt;id&gt;)
when metadata is edited and leaves the old directory behind, so a miss retries
by the stable book id before reporting MISSING - which distinguishes "the file
is not here right now" from "no such document". The gate tests for metadata.db
rather than the directory, since an unmounted or half-synced mountpoint is
still a directory.

Consumers that prescribed their own tree search - driver-reviewer, port-dev,
the driver-review workflow, and the calibre-library references in CLAUDE.md,
usbtest, etm-trace and target-debug - now point at the skill, which owns the
library's location.
</content>
</entry>
<entry>
<title>docs: hand off follow-up work as per-PR plans</title>
<updated>2026-08-18T05:19:09Z</updated>
<author>
<name>hathach</name>
<email>thach@tinyusb.org</email>
</author>
<published>2026-08-17T12:20:32Z</published>
<link rel='alternate' type='text/html' href='http://cgit.235523.xyz/tinyusb.git/commit/?id=c7290c4d3167766055f492de43f1ede83940e23c'/>
<id>urn:sha1:c7290c4d3167766055f492de43f1ede83940e23c</id>
<content type='text'>
Records the convention in CLAUDE.md -- deferred work is a SEPARATE scope that deserves
its own PR, written by another session, so it is handed off as a writing-plans doc in
docs/superpowers/followup/pr&lt;NNN&gt;-&lt;topic&gt;.md rather than accumulated in the PR that
found it.

Five handoffs from #3803: flasher_recover (convoy-safe recovery for J-Link boards, seven
validated on the rig), the blindness reporting gaps, the usbtest recovery reserve, the
IAR re-run spec, and the pci-rebind stranding question. Each carries what is already
established with its citations and measurements, what remains, and why it was split out.

One doc per follow-up, not one per PR: a per-PR file invites unrelated work into the
same document and rots as a unit.
</content>
</entry>
<entry>
<title>skills, docs: rewrite USB recovery from the live incidents</title>
<updated>2026-08-18T05:19:09Z</updated>
<author>
<name>hathach</name>
<email>thach@tinyusb.org</email>
</author>
<published>2026-08-13T18:08:50Z</published>
<link rel='alternate' type='text/html' href='http://cgit.235523.xyz/tinyusb.git/commit/?id=f822f69a9871b2115c5213889d70411da66ca1b1'/>
<id>urn:sha1:f822f69a9871b2115c5213889d70411da66ca1b1</id>
<content type='text'>
Two things the rig taught us that the old guidance got wrong.

A usbfs ioctl wedged in D state cannot be freed on a running kernel. It holds
the device lock, so usb_disconnect() blocks behind it; reboot(2) walks
device_shutdown() and takes the same lock, so every userspace reboot stalls too.
Only sysrq b (emergency_restart, which skips device_shutdown) or hypervisor
action clears it -- all cited to the kernel source. The recovery ladder is
generic across rigs now (ci.lan, hifiphile, a bench PC) and ends at hypervisor
escalation only where host access exists. Two claims are corrected outright:
JLinkExe is NOT convoy-safe, and a park-flash cannot free a device-lock owner.

The hil skill's banner list is what an operator agent matches a report against,
so it enumerates the banners that actually exist, including the D-state note --
which is explicitly NOT a wedge, since a healthy in-flight testusb is
uninterruptible for most of every case and a concurrent CI battery would
otherwise turn a clean run red.
</content>
</entry>
<entry>
<title>test/hil, ci: contain a wedged USB stack instead of stranding the runner</title>
<updated>2026-08-18T05:19:09Z</updated>
<author>
<name>hathach</name>
<email>thach@tinyusb.org</email>
</author>
<published>2026-08-13T18:08:40Z</published>
<link rel='alternate' type='text/html' href='http://cgit.235523.xyz/tinyusb.git/commit/?id=3963a1b70a572132aced1c1a0033e1c8249a0c7e'/>
<id>urn:sha1:3963a1b70a572132aced1c1a0033e1c8249a0c7e</id>
<content type='text'>
A wedged USB device used to take the whole HIL run with it. Every worker that
touched the poisoned node blocked uninterruptibly, the pool could not be joined,
map_async discarded every board's result, and the job ran to the GitHub ceiling
with no report at all -- while the self-hosted runner's single job slot stayed
occupied and every queued job waited behind it.

Bound the calls a worker makes itself. read_sysfs, bounded_open and run_cmd all
answer within a wall clock; read_sysfs distinguishes "absent" from "unknown",
because a blocked read is not evidence of absence, and caps stranded readers at
four (each costs a thread and an fd for the life of the process) after which the
worker declares itself blind. mtype, the gio unmount, the libmtp session and the
arecord/iperf reaps go through those bounds; the MTP session runs in a disposable
subprocess, since libmtp's ctypes calls block unkillably in D state.

Bound the run. A pool guard (HIL_POOL_TIMEOUT, 60 min) fires before any job
ceiling and still writes a report. When the pool will not shut down, the sweep
kills what the workers spawned -- descendants, not just direct children, since
flashers run in their own session -- confirms each kill actually landed, and
exits early so the runner is freed. Whatever survived is named in the report.

Deliberately shallow past that point. We do not re-scan process groups, prove
pid ownership, or escalate through sudo: a root-owned survivor is reported, not
force-killed, because signalling a pid we cannot prove is ours is the worse
failure, and the job ceiling backstops whatever this misses. A D-state holder
was never killable anyway.

Recover instead of reporting a wedge. A HUNG usbtest case reflashes its own DUT
through its roster flasher, but only where the flasher can reach its probe past
a poisoned node -- openocd pinned to a validated vid_pid, or esptool. Where it
cannot, the run says so rather than reserving budget for a path that cannot fire.

Raise the CI ceilings above the pool guard so the guard fires first and still
writes its report, and pin --retry 1 on every HIL leg: the guard is a flat
constant and does not scale with max_retry, so argparse's default of 3 would
triple the serialized usbtest tail against an unchanged guard.

Split the module: execution in hil_test/hil_flash/usbtest, infrastructure in
helper/ (locking, health, selection, shared bounded IO), and the two matrix
generators into .github/scripts/ -- ci_set_matrix.py sat in workflows/, where
GitHub treats every file as a workflow definition. 193 tests cover the bounded
paths, the kill ladder, the guard and the selector against synthetic /proc trees
and PATH-injected fakes; a real wedge cannot be manufactured on demand.
</content>
</entry>
<entry>
<title>docs: add the unified OpenOCD plan, note worktree dep symlinks</title>
<updated>2026-07-28T07:43:32Z</updated>
<author>
<name>hathach</name>
<email>thach@tinyusb.org</email>
</author>
<published>2026-07-28T07:43:32Z</published>
<link rel='alternate' type='text/html' href='http://cgit.235523.xyz/tinyusb.git/commit/?id=3fdd294b95143f909a6c991943a2e55e638b177a'/>
<id>urn:sha1:3fdd294b95143f909a6c991943a2e55e638b177a</id>
<content type='text'>
The plan doc records why the fork exists and how each vendor source was
ported; the interim handoff it superseded is dropped.

CLAUDE.md: a new worktree should symlink the dependency dirs to the
primary checkout rather than re-fetching them, replacing a single
symlink only when the branch needs a different dep revision. Also allow
'linke' in codespell - WCH-LinkE is a product name.
</content>
</entry>
<entry>
<title>docs(skills): rename debug skills, drop the PC-host/TinyUSB-device assumption</title>
<updated>2026-07-24T07:55:59Z</updated>
<author>
<name>hathach</name>
<email>thach@tinyusb.org</email>
</author>
<published>2026-07-23T03:18:11Z</published>
<link rel='alternate' type='text/html' href='http://cgit.235523.xyz/tinyusb.git/commit/?id=8918c4fec4a99b174d480c043000fd4405678282'/>
<id>urn:sha1:8918c4fec4a99b174d480c043000fd4405678282</id>
<content type='text'>
Rename usb-target-debug -&gt; target-debug, usb-debug -&gt; usb-kernel-debug,
usb-recover -&gt; 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
</content>
</entry>
<entry>
<title>docs: add read-doc skill, tighten CLAUDE.md and skill docs (#3778)</title>
<updated>2026-07-21T11:06:01Z</updated>
<author>
<name>Ha Thach</name>
<email>thach@tinyusb.org</email>
</author>
<published>2026-07-21T11:06:01Z</published>
<link rel='alternate' type='text/html' href='http://cgit.235523.xyz/tinyusb.git/commit/?id=1b5c26b76e7194d05b82b0cccf76684716d3374d'/>
<id>urn:sha1:1b5c26b76e7194d05b82b0cccf76684716d3374d</id>
<content type='text'>
* 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 -&gt; 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.</content>
</entry>
<entry>
<title>docs: make CLAUDE.md the real agent-instructions file (#3769)</title>
<updated>2026-07-21T05:35:00Z</updated>
<author>
<name>Ha Thach</name>
<email>thach@tinyusb.org</email>
</author>
<published>2026-07-21T05:35:00Z</published>
<link rel='alternate' type='text/html' href='http://cgit.235523.xyz/tinyusb.git/commit/?id=c6a1c66f8a64446ad1160b8e5b2da88ad1f3eac5'/>
<id>urn:sha1:c6a1c66f8a64446ad1160b8e5b2da88ad1f3eac5</id>
<content type='text'>
* docs: make CLAUDE.md the real agent-instructions file</content>
</entry>
<entry>
<title>fix trailing newline in workflow files to pass pre-commit</title>
<updated>2026-03-04T11:13:51Z</updated>
<author>
<name>hathach</name>
<email>thach@tinyusb.org</email>
</author>
<published>2026-03-04T11:13:51Z</published>
<link rel='alternate' type='text/html' href='http://cgit.235523.xyz/tinyusb.git/commit/?id=f021d5c1e1de5c1b47fcbdd6d8fb1eea70eafe61'/>
<id>urn:sha1:f021d5c1e1de5c1b47fcbdd6d8fb1eea70eafe61</id>
<content type='text'>
Co-Authored-By: Claude Sonnet 4.6 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>focus on cdc test, write lots more data, each trunk is 64 or less since examples having minimum 64 bytes fifo (fs)</title>
<updated>2025-11-26T06:54:04Z</updated>
<author>
<name>hathach</name>
<email>thach@tinyusb.org</email>
</author>
<published>2025-11-22T11:26:43Z</published>
<link rel='alternate' type='text/html' href='http://cgit.235523.xyz/tinyusb.git/commit/?id=67ba8eab2e346dc13cce3d0813de6370cb3cfa48'/>
<id>urn:sha1:67ba8eab2e346dc13cce3d0813de6370cb3cfa48</id>
<content type='text'>
</content>
</entry>
</feed>
