Reviewing hardware discovery: reads that could wake a device, and a Linux premise that CI disproved
An adversarial review of the Phase 4 hardware discovery confirmed 68 of 77 de-duplicated findings, 5 of them blockers such as link reads that could wake a suspended device and a virtual-machine bus identifier reaching the output; all 68 were fixed, and a review of the fixes found 10 regressions, each verified and fixed before the gate.
What was done
Ran an adversarial review of the Phase 4 hardware-discovery implementation before its gate: thirteen reviewers raised 86 findings, and a separate verifier per finding tried to refute each one, leaving 68 confirmed, 5 of them blockers. The lead settled the findings whose fix had options in written decisions, seven fix owners fixed 67 and partly fixed one, which was completed afterwards, and a further review of the fix diff found 10 regressions, which were verified and fixed in turn. Several confirmed findings rested on CI evidence: the first Linux run had shown that a premise of the identity design was false.
10 reviewers, one dimension each 75 raised
3 fresh-eyes reviewers +11 raised
de-duplicated 77
a verifier per finding tries to 9 refuted
refute it (21 by reproduction too) 68 confirmed
blocker / major / minor 5 / 12 / 51
7 fix owners 67 fixed, 1 partly
review of the fix diff 10 regressions
each claim verified, then fixed 10 of 10 held
the partly fixed finding completedEvery confirmed finding and every regression claim was checked against the code before anything was changed.
Status
The review ran on 8 October 2026 on the implementation, once the independent test vectors and the identifier wrapper were complete; the first CI run had been on the implementation as committed in c48b9c1. The fixes, the review of the fixes and the remediation were completed on 9 October. A gate agent ran the full local gate on the development PC, and every line passed; the fixed tree was then committed for CI as 1284f98. The phase was committed as 5a7cdcb on 9 October, and CI passed on it on Linux and Windows, including the Linux real-hardware steps as a standard user and as root, on GitHub's Linux virtual machine (run 37969013522).
The problem
The implementation had passed its own tests, and a phase that adds direct device access and new identifier sources needs more than that before its gate. The review asked one question per dimension: device safety, privacy, the Windows providers, the Linux providers, the parsers, the provider model and isolation, identity and sessions, the contract and its migration, tests and CI, and whether the documents were true. Three fresh-eyes reviewers were given no dimension and looked across them. The five blockers it confirmed were these:
- Link reads that could wake a device. On Linux the PCI Express link attributes of every GPU, network card and NVMe controller were read with no check of the device's power state. Since Linux 6.18 such a read resumes a suspended device, so a scan of a hybrid-graphics laptop could power up its sleeping discrete GPU straight after recording that it had not woken it.
- Values decoded from an all-ones read. On kernels without that resume, the same read of a powered-down device returns all ones, which decodes as a 63-lane link and, on older kernels, a maximum speed of 64 GT/s, and it was recorded as a measured value.
- A virtual-machine bus identifier in the output. Two Linux sources built their recorded source path from the resolved device path. On a Hyper-V or Azure virtual machine that path contains the instance identifier of the virtual bus device, so the identifier would have reached the output.
- A display location that was invented. On Windows, a display adapter that is not a PCI device, such as a USB docking adapter, was given a well-formed PCI location built from properties that mean something else on USB, and it was recorded as available.
- A product code with no evidence. When a monitor's EDID could not be read, the fallback recorded a product code of 0000 as available without checking the flag that says the identifiers are valid.
The premise CI disproved
The design held that a Linux scan without root is always weakly identified, because the machine identifiers it relies on are readable only by root. The first CI run, 37770432456 on c48b9c1, showed otherwise: on GitHub's Linux runner one of those identifiers was readable without root while another was denied. The scan identified the machine from the readable one, keyed every component, and failed three real-hardware tests; the release-mode and root steps of that job were then skipped. Reviewers in three dimensions confirmed the consequence: on one machine the fingerprint and every key would depend on privilege, so the same device could be recorded under two keys.
The change. If any identifier read is denied, the machine identity is now weak: no fingerprint, no keys and no boot identity, with the reason recorded. An identifier that is simply absent still drops out, because absence does not depend on privilege. Windows never denies such a read, so its fingerprints and keys are unchanged. CI run 37945526956 on 1284f98 then passed the Linux real-hardware steps both as a standard user and as root.
How each class was fixed
| Class | What changed |
|---|---|
| Reads that could change device state | Every PCI Express link read, and every read of network speed and duplex, now happens only after the device's power state shows it awake; a suspended device's values are recorded as unavailable with that reason. On Windows the disk-geometry query goes to NVMe disks only, and a disk whose nearest PCI function is not an NVMe controller, as behind Intel VMD or RST, is not queried through it |
| Implausible values | A link width is accepted only if PCI Express can encode it; a placeholder firmware version and an unflagged display identifier are recorded as unavailable with their reasons, and a truncated firmware table is no longer treated as complete |
| Identifiers in sources | Linux sources use fixed path templates, never a resolved device path |
| Invented locations | A display adapter that is not enumerated by PCI gets no PCI location |
| Identity across privilege | The weak-identity rule above, with a test double for a host where one identifier is readable and another is denied |
| Tests that could not catch the failure | CI now runs the parser mutation loop at its full 10,000 iterations per vector, with a job time limit and a watchdog that names the vector and iteration of a looping parser |
The lead recorded 13 decisions where a fix had options or changed the design, and every other finding was fixed as reported.
How the fixes were verified
The Linux, Windows, parser and identity fix owners reverted their fixes and showed the new tests failing before restoring them. For two contract findings the run before the fix was not repeated; their fixed state is shown by the passing suites. One finding, a lint rule for identifier-like member names, was only partly fixed in the fix round: its code was fixed, but two documents still described the old rule, and they were corrected in the remediation.
The review of the fixes
A review of the fix diff raised 10 regression claims, 2 major and 8 minor. Each was checked against the code and against kernel or operating-system behaviour before it was fixed, and all 10 held. The two majors:
- Every USB network adapter would have read as suspended. The new guard looked for power-state information that the kernel does not normally provide for a USB network interface, so every USB adapter with its link up would have recorded its speed as unavailable, giving as the reason that the device was suspended. The guard was corrected: an awake USB adapter is no longer reported as suspended, and a power state that cannot be read is recorded as unreadable, not as asleep.
- A real-hardware test contradicted a fix. A display-year fix allowed a year to be absent, but a real-hardware test still required exactly one; the test now allows absence only for the case the EDID standard reserves.
Every regression fix except two (a documentation comment and a tightened assertion) has a test that was run against the old behaviour and shown to fail.
Results
| Measure | Count |
|---|---|
| Findings raised | 86 |
| After de-duplication | 77 |
| Refuted | 9 |
| Confirmed | 68 |
| Graded blocker / major / minor | 5 / 12 / 51 |
| Fixed in the fix round | 67 |
| Partly fixed, then completed | 1 |
| Regression claims on the fixes | 10, all confirmed and fixed |
The local gate after the fixes passed with 669 Rust tests, 101 C# and 1,426 TypeScript, and the release-mode suites. In CI run 37945526956 on 1284f98, the Rust jobs on Linux and Windows and the C# job passed; the TypeScript job was lost when the runner received a shutdown signal (exit code 143), with every test it had reported passing, and the same happened in run 37955092438 on f809348. The next run, 37962027634 on 34aa7fc, traced the shutdowns to database tests that used up the runner's memory, and after 78a111e closed each test database after its test, run 37963842380 passed all four jobs. Neither commit is the gate commit; on the gate commit, 5a7cdcb, run 37969013522 passed all four jobs too.
Limitations
- Shared model family. The reviewers, the refuting verifiers, the fix owners and the lead are instances of the same underlying system, so their blind spots may be correlated. CI and real hardware are the checks outside the model; the false identity premise was exposed by a CI run, not by reading the code.
- Refutations were not re-checked. Whether the nine refuted findings were rightly refuted was not independently checked.
- Many fixes are proved only on synthetic devices. The power-state guards and the Linux paths were tested on synthetic device trees and in CI's virtual machines, not on a laptop with a sleeping discrete GPU or a USB network adapter.
- No elevated run on real hardware. The elevated path was exercised only on GitHub's Windows runner, whose disks are virtual.
Open questions
Whether the guards behave as intended on physical hybrid-graphics and USB-network hardware was not shown at the time of this record.
The code
How a decoded link width is accepted: only the widths PCI Express can encode pass, so the 63 lanes that an all-ones read decodes to are refused with a reason instead of being recorded.
pub const LINK_WIDTHS: [u32; 7] = [1, 2, 4, 8, 12, 16, 32];
// ...
pub fn link_width(lanes: u32) -> Result<i64, String> {
if lanes == 0 {
Err(LINK_DOWN_REASON.into())
} else if LINK_WIDTHS.contains(&lanes) {
Ok(i64::from(lanes))
} else {
Err(implausible_width_reason(lanes))
}
}core/hardware/src/parse/pci.rs, as it stands at the Phase 4 commit 5a7cdcb (unchanged since 1284f98) — the constant and the function, without their doc comments; the lines between them are elided.
Not shown. The power-state guard, the identifier wrapper, the weak-identity rule's implementation and the identity schemes are withheld, because they are safeguards or identity mechanisms still in use. Apart from the five blockers, which are described as problems and outcomes, individual findings are described only at summary level, and the lead's decisions are not published.
A published copy. Commit references and internal identifiers have been removed and the operator is not named; the engineering, the counts and the stated limits are unchanged.