)]}'
{
  "commit": "3963a1b70a572132aced1c1a0033e1c8249a0c7e",
  "tree": "f612deb9c6dc878984ba59c72c74f04741925187",
  "parents": [
    "2465ea8f435114af3b3c935cc4fbed423d9eac69"
  ],
  "author": {
    "name": "hathach",
    "email": "thach@tinyusb.org",
    "time": "Fri Aug 14 01:08:40 2026 +0700"
  },
  "committer": {
    "name": "hathach",
    "email": "thach@tinyusb.org",
    "time": "Tue Aug 18 12:19:09 2026 +0700"
  },
  "message": "test/hil, ci: contain a wedged USB stack instead of stranding the runner\n\nA wedged USB device used to take the whole HIL run with it. Every worker that\ntouched the poisoned node blocked uninterruptibly, the pool could not be joined,\nmap_async discarded every board\u0027s result, and the job ran to the GitHub ceiling\nwith no report at all -- while the self-hosted runner\u0027s single job slot stayed\noccupied and every queued job waited behind it.\n\nBound the calls a worker makes itself. read_sysfs, bounded_open and run_cmd all\nanswer within a wall clock; read_sysfs distinguishes \"absent\" from \"unknown\",\nbecause a blocked read is not evidence of absence, and caps stranded readers at\nfour (each costs a thread and an fd for the life of the process) after which the\nworker declares itself blind. mtype, the gio unmount, the libmtp session and the\narecord/iperf reaps go through those bounds; the MTP session runs in a disposable\nsubprocess, since libmtp\u0027s ctypes calls block unkillably in D state.\n\nBound the run. A pool guard (HIL_POOL_TIMEOUT, 60 min) fires before any job\nceiling and still writes a report. When the pool will not shut down, the sweep\nkills what the workers spawned -- descendants, not just direct children, since\nflashers run in their own session -- confirms each kill actually landed, and\nexits early so the runner is freed. Whatever survived is named in the report.\n\nDeliberately shallow past that point. We do not re-scan process groups, prove\npid ownership, or escalate through sudo: a root-owned survivor is reported, not\nforce-killed, because signalling a pid we cannot prove is ours is the worse\nfailure, and the job ceiling backstops whatever this misses. A D-state holder\nwas never killable anyway.\n\nRecover instead of reporting a wedge. A HUNG usbtest case reflashes its own DUT\nthrough its roster flasher, but only where the flasher can reach its probe past\na poisoned node -- openocd pinned to a validated vid_pid, or esptool. Where it\ncannot, the run says so rather than reserving budget for a path that cannot fire.\n\nRaise the CI ceilings above the pool guard so the guard fires first and still\nwrites its report, and pin --retry 1 on every HIL leg: the guard is a flat\nconstant and does not scale with max_retry, so argparse\u0027s default of 3 would\ntriple the serialized usbtest tail against an unchanged guard.\n\nSplit the module: execution in hil_test/hil_flash/usbtest, infrastructure in\nhelper/ (locking, health, selection, shared bounded IO), and the two matrix\ngenerators into .github/scripts/ -- ci_set_matrix.py sat in workflows/, where\nGitHub treats every file as a workflow definition. 193 tests cover the bounded\npaths, the kill ladder, the guard and the selector against synthetic /proc trees\nand PATH-injected fakes; a real wedge cannot be manufactured on demand.\n",
  "tree_diff": [
    {
      "type": "modify",
      "old_id": "66799910d41b23356927659d44389f6b96cfedf8",
      "old_mode": 33188,
      "old_path": ".circleci/config.yml",
      "new_id": "48fa87899e7882a7272e0631ca799461731bf36f",
      "new_mode": 33188,
      "new_path": ".circleci/config.yml"
    },
    {
      "type": "rename",
      "old_id": "50ada5964fcc30a581e0b6ee063922a6f36d09b0",
      "old_mode": 33261,
      "old_path": ".github/workflows/ci_set_matrix.py",
      "new_id": "50ada5964fcc30a581e0b6ee063922a6f36d09b0",
      "new_mode": 33261,
      "new_path": ".github/scripts/ci_set_matrix.py",
      "score": 100
    },
    {
      "type": "rename",
      "old_id": "bca989bd15fe5743c8a1e54a5184a0036450f6ac",
      "old_mode": 33188,
      "old_path": "test/hil/hil_ci_set_matrix.py",
      "new_id": "65f50788e37525b5b5ccc903a17f960378ceff05",
      "new_mode": 33188,
      "new_path": ".github/scripts/hil_ci_set_matrix.py",
      "score": 90
    },
    {
      "type": "modify",
      "old_id": "bdef81553ba595886385b9da93a2eb0be55b49d1",
      "old_mode": 33188,
      "old_path": ".github/workflows/build.yml",
      "new_id": "8f6014f48b696399599c5715b3917454fb41648f",
      "new_mode": 33188,
      "new_path": ".github/workflows/build.yml"
    },
    {
      "type": "modify",
      "old_id": "70dd3894d0536be11014f37716cd9a65feaa6951",
      "old_mode": 33188,
      "old_path": ".github/workflows/pre-commit.yml",
      "new_id": "09f912bd3a5a761a67a2dfdb0e7b77ebd835742b",
      "new_mode": 33188,
      "new_path": ".github/workflows/pre-commit.yml"
    },
    {
      "type": "modify",
      "old_id": "e87b935dd9bb36bfcb8c00be1bd2e67a4c7a3513",
      "old_mode": 33188,
      "old_path": ".pre-commit-config.yaml",
      "new_id": "3d9c8482b0f818d2b95370350d3a02f5fdfd727c",
      "new_mode": 33188,
      "new_path": ".pre-commit-config.yaml"
    },
    {
      "type": "modify",
      "old_id": "94b8192b736b3cf9d4ebceafff76fd765bb72831",
      "old_mode": 33188,
      "old_path": "CLAUDE.md",
      "new_id": "fd4b9b8e01c523f76929f15175ba64840b48d8f1",
      "new_mode": 33188,
      "new_path": "CLAUDE.md"
    },
    {
      "type": "modify",
      "old_id": "8158758bc3af3c48061f37dcc9cce101e41302a4",
      "old_mode": 33188,
      "old_path": "docs/superpowers/specs/2026-07-29-hil-pr-scoped-selection-design.md",
      "new_id": "898b3c8ab0a2eda9264a31e300b597a140293722",
      "new_mode": 33188,
      "new_path": "docs/superpowers/specs/2026-07-29-hil-pr-scoped-selection-design.md"
    },
    {
      "type": "modify",
      "old_id": "60f43e152b8132f56d14247b4353f8aaf4af6f9d",
      "old_mode": 33188,
      "old_path": "hw/bsp/mcx/family.cmake",
      "new_id": "b2b4fd45b3bbb99d893741c76b03d0402c2c5819",
      "new_mode": 33188,
      "new_path": "hw/bsp/mcx/family.cmake"
    },
    {
      "type": "add",
      "old_id": "0000000000000000000000000000000000000000",
      "old_mode": 0,
      "old_path": "/dev/null",
      "new_id": "a080a2f551aec65ab88c57fd00f06780cf30e860",
      "new_mode": 33188,
      "new_path": "test/hil/helper/__init__.py"
    },
    {
      "type": "add",
      "old_id": "0000000000000000000000000000000000000000",
      "old_mode": 0,
      "old_path": "/dev/null",
      "new_id": "92f0accc88a855c37d9d97057b63e21a668e260d",
      "new_mode": 33188,
      "new_path": "test/hil/helper/hil_health.py"
    },
    {
      "type": "rename",
      "old_id": "e570da16a03ece9bd2c92b80fdc430624723e043",
      "old_mode": 33261,
      "old_path": "test/hil/hil_lock.py",
      "new_id": "7757ef17de7eee71517e95af5668f969eb4ffc91",
      "new_mode": 33261,
      "new_path": "test/hil/helper/hil_lock.py",
      "score": 66
    },
    {
      "type": "rename",
      "old_id": "98f24288a6932fa68f3719ee801a1734f6294046",
      "old_mode": 33188,
      "old_path": "test/hil/hil_pool_check.py",
      "new_id": "371aff1e19dd189f8811d6d70ac894678de84021",
      "new_mode": 33188,
      "new_path": "test/hil/helper/hil_pool_check.py",
      "score": 79
    },
    {
      "type": "rename",
      "old_id": "3ac3f1fdb3e572bc3750c4aea5e33f13623b7d28",
      "old_mode": 33261,
      "old_path": "test/hil/hil_select.py",
      "new_id": "f0d4f0b9fe7bd4198d856d764df396d6145d6676",
      "new_mode": 33261,
      "new_path": "test/hil/helper/hil_select.py",
      "score": 96
    },
    {
      "type": "add",
      "old_id": "0000000000000000000000000000000000000000",
      "old_mode": 0,
      "old_path": "/dev/null",
      "new_id": "54984d20f5754dd9b47cc6c3be98b73ea7864240",
      "new_mode": 33188,
      "new_path": "test/hil/helper/hil_util.py"
    },
    {
      "type": "modify",
      "old_id": "ef93bcb4997677ddbf1ffb3644f8fdd2d8497d6b",
      "old_mode": 33188,
      "old_path": "test/hil/hil_ci.sh",
      "new_id": "c7dfa95dfe95534fcb5bbd55eb7e9a32b7083da2",
      "new_mode": 33188,
      "new_path": "test/hil/hil_ci.sh"
    },
    {
      "type": "delete",
      "old_id": "4c8b6918bd92ea769fed76294d21f3488922e082",
      "old_mode": 33188,
      "old_path": "test/hil/hil_examples.py",
      "new_id": "0000000000000000000000000000000000000000",
      "new_mode": 0,
      "new_path": "/dev/null"
    },
    {
      "type": "modify",
      "old_id": "da81fcc970ab00db609e85937670bed0c546e3c1",
      "old_mode": 33261,
      "old_path": "test/hil/hil_flash.py",
      "new_id": "f4bed45a612ef40aa486e9125888d1df395a0bd1",
      "new_mode": 33261,
      "new_path": "test/hil/hil_flash.py"
    },
    {
      "type": "modify",
      "old_id": "5d94078836685c89ba13c6605b5d3dc1e0eb735c",
      "old_mode": 33261,
      "old_path": "test/hil/hil_test.py",
      "new_id": "1742513433642fe57b5486d5783b01894c597eb7",
      "new_mode": 33261,
      "new_path": "test/hil/hil_test.py"
    },
    {
      "type": "add",
      "old_id": "0000000000000000000000000000000000000000",
      "old_mode": 0,
      "old_path": "/dev/null",
      "new_id": "92d54bdbebc2b0557edd874f1a881286ec9e59b6",
      "new_mode": 33188,
      "new_path": "test/hil/mtp_test.py"
    },
    {
      "type": "add",
      "old_id": "0000000000000000000000000000000000000000",
      "old_mode": 0,
      "old_path": "/dev/null",
      "new_id": "2720321f6bd40ea5b53a7fcc5ca3dfc1c2f1b531",
      "new_mode": 33188,
      "new_path": "test/hil/test/stubs/pymtp.py"
    },
    {
      "type": "add",
      "old_id": "0000000000000000000000000000000000000000",
      "old_mode": 0,
      "old_path": "/dev/null",
      "new_id": "908a142d52a6ef0231d4b5e573281cefa07c892a",
      "new_mode": 33188,
      "new_path": "test/hil/test/test_hil_bounded.py"
    },
    {
      "type": "add",
      "old_id": "0000000000000000000000000000000000000000",
      "old_mode": 0,
      "old_path": "/dev/null",
      "new_id": "5695cad6d160eae512f2f305cf41a358aa0753aa",
      "new_mode": 33188,
      "new_path": "test/hil/test/test_hil_health.py"
    },
    {
      "type": "rename",
      "old_id": "5e6b16759cbb08daa189e8b1b01a411bb2588c7b",
      "old_mode": 33188,
      "old_path": "test/hil/test_hil_select.py",
      "new_id": "9a1261878666638b3337f807062f726caf9bfb59",
      "new_mode": 33188,
      "new_path": "test/hil/test/test_hil_select.py",
      "score": 79
    },
    {
      "type": "add",
      "old_id": "0000000000000000000000000000000000000000",
      "old_mode": 0,
      "old_path": "/dev/null",
      "new_id": "9c3d5edef60497dad6312a63269ef91b9e6f3ee3",
      "new_mode": 33188,
      "new_path": "test/hil/test/test_hil_util.py"
    },
    {
      "type": "modify",
      "old_id": "c9b38992c1a3bb1c7677a5c7bfbd5e3046b1d7f9",
      "old_mode": 33188,
      "old_path": "test/hil/tinyusb.json",
      "new_id": "549a17cd008fa1b7a3655a0a5ef3f7ed443a94f7",
      "new_mode": 33188,
      "new_path": "test/hil/tinyusb.json"
    },
    {
      "type": "modify",
      "old_id": "83ea3e24c019f082fa511f4789f9c2343881ba52",
      "old_mode": 33261,
      "old_path": "test/hil/usbtest.py",
      "new_id": "485e9e0e446d88a9103a59d4a0b7d14208acbd03",
      "new_mode": 33261,
      "new_path": "test/hil/usbtest.py"
    },
    {
      "type": "modify",
      "old_id": "799a9680020e30f1bbf2592767652b037afc17be",
      "old_mode": 33188,
      "old_path": "tools/metrics_compare_base.py",
      "new_id": "844130097a1bf364085bf01779f50a8564d7715c",
      "new_mode": 33188,
      "new_path": "tools/metrics_compare_base.py"
    }
  ]
}
