)]}'
{"cyborg/accelerator/drivers/nvme/driver.py":[{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"07c645424e723deff16e93e504bc5fe1d16bff28","unresolved":false,"context_lines":[{"line_number":64,"context_line":"        path \u003d pathlib.Path(self._pci_sysfs_path) / pci_address / filename"},{"line_number":65,"context_line":"        try:"},{"line_number":66,"context_line":"            return path.read_text().strip().removeprefix(\u00270x\u0027)"},{"line_number":67,"context_line":"        except Exception:"},{"line_number":68,"context_line":"            return \u0027unknown\u0027"},{"line_number":69,"context_line":""},{"line_number":70,"context_line":"    def _enumerate_nvme_pci_devices(self):"}],"source_content_type":"text/x-python","patch_set":2,"id":"522b6950_3560a06a","line":67,"updated":"2026-08-06 11:00:08.000000000","message":"Three locations in the new driver.py use bare `except Exception:` for file I/O and subprocess operations. The OpenStack style guide requires specific exception types. These broad catches could mask programming errors like AttributeError or TypeError as silent fallbacks.\n\n**Severity**: WARNING | **Confidence**: 0.8\n\n**Impact**: Broad exception handlers in device discovery can silently mask programming bugs (e.g., an AttributeError from a None value) by treating them as expected I/O failures. A device that should raise an error during development instead silently disappears from the pool with no actionable diagnostic bey...\n\n**Suggestion**:\nReplace `except Exception:` with specific exception types: `OSError` for file reads in `_read_sysfs_id` and `_enumerate_nvme_pci_devices`; `(exception.DeviceNotFound, processutils.ProcessExecutionError)` for `_query_capabilities` in `discover()`.","commit_id":"a767f912bd7dd82515b099bf9bd81cd6894d41be"},{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"07c645424e723deff16e93e504bc5fe1d16bff28","unresolved":false,"context_lines":[{"line_number":140,"context_line":""},{"line_number":141,"context_line":"        return None"},{"line_number":142,"context_line":""},{"line_number":143,"context_line":"    def _build_traits(self, vendor_id, product_id, caps):"},{"line_number":144,"context_line":"        traits \u003d [constants.OWNER_CYBORG]"},{"line_number":145,"context_line":"        traits.append(\u0027CUSTOM_NVME_PRODUCT_ID_%s\u0027 % product_id.upper())"},{"line_number":146,"context_line":"        if caps[\u0027ces\u0027]:"}],"source_content_type":"text/x-python","patch_set":2,"id":"99350085_e40c514a","line":143,"updated":"2026-08-06 11:00:08.000000000","message":"The _build_traits method accepts vendor_id as its first parameter but never references it in the method body. The caller passes vendor_id but it has no effect on the output.\n\n**Severity**: SUGGESTION | **Confidence**: 0.9\n\n**Benefit**: The unused parameter is misleading — future maintainers may assume vendor_id is used for trait generation. It also makes the method signature wider than necessary.\n\n**Recommendation**:\nRemove the vendor_id parameter from _build_traits and update the call site at line 228 to not pass it. If vendor-specific traits are planned for the future, add a comment explaining the intent.","commit_id":"a767f912bd7dd82515b099bf9bd81cd6894d41be"},{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"37c01b150be1a809eddb9072a7d0d6e1d0af1525","unresolved":false,"context_lines":[{"line_number":11,"context_line":"# License for the specific language governing permissions and limitations"},{"line_number":12,"context_line":"# under the License."},{"line_number":13,"context_line":""},{"line_number":14,"context_line":"import pathlib"},{"line_number":15,"context_line":""},{"line_number":16,"context_line":"from oslo_log import log as logging"},{"line_number":17,"context_line":"from oslo_serialization import jsonutils"}],"source_content_type":"text/x-python","patch_set":4,"id":"b4e2af26_303de035","line":14,"updated":"2026-08-06 16:51:09.000000000","message":"The new file cyborg/accelerator/drivers/nvme/driver.py has no module-level docstring after the Apache license header. Every other driver module in the project includes one (e.g., \u0027Cyborg NVIDIA GPU driver implementation.\u0027, \u0027Cyborg PCI driver implementation.\u0027, \u0027Cyborg Intel FPGA driver implementat...\n\n**Severity**: SUGGESTION | **Confidence**: 0.9\n\n**Benefit**: Reduces discoverability and self-documentation of the module. New contributors and automated documentation tools cannot determine the module\u0027s purpose from a standard docstring. Minor maintainability concern for a new production module.\n\n**Recommendation**:\nAdd a module-level docstring after the license header, e.g.: \u0027\\n\"\"\"Cyborg NVMe accelerator driver implementation.\"\"\"\\n\u0027","commit_id":"4b1a9cf3f76b167bc0928f088e911a3cc80210d9"},{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"af99da5739eed8ae74d7e36401d20f0efb340a49","unresolved":false,"context_lines":[{"line_number":208,"context_line":""},{"line_number":209,"context_line":"            try:"},{"line_number":210,"context_line":"                caps \u003d self._query_capabilities(pci_addr)"},{"line_number":211,"context_line":"            except Exception:"},{"line_number":212,"context_line":"                LOG.exception("},{"line_number":213,"context_line":"                    \u0027Failed to query capabilities for %s\u0027,"},{"line_number":214,"context_line":"                    pci_addr,"}],"source_content_type":"text/x-python","patch_set":5,"id":"405f2989_cfaafa2d","line":211,"updated":"2026-08-07 07:02:11.000000000","message":"NVMeDriver.discover() catches `except Exception:` around _query_capabilities(). While the intent is to skip devices that fail nvme-cli queries, the broad catch also swallows programming errors (TypeError, AttributeError, KeyError) that indicate real bugs. The project quick rules list \u0027no broad Ex...\n\n**Severity**: SUGGESTION | **Confidence**: 0.8\n\n**Benefit**: Unexpected programming errors (e.g., nvme-cli output format change causing KeyError) would be silently logged and the device excluded from the pool without operator awareness. This makes debugging harder in production.\n\n**Recommendation**:\nReplace `except Exception:` with specific exceptions: `except (exception.DeviceNotFound, processutils.ProcessExecutionError, ValueError, OSError):`. This preserves skip-on-failure behavior while allowing truly unexpected errors to surface.","commit_id":"a1079c30416c0f14b9da5db329efe1678c515ba9"},{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"6f6d87758d679a0776bac9db7b8314c6d03ded16","unresolved":false,"context_lines":[{"line_number":290,"context_line":"                )"},{"line_number":291,"context_line":"                continue"},{"line_number":292,"context_line":""},{"line_number":293,"context_line":"            if self._rp_exists_without_owner_cyborg(hostname, pci_addr):"},{"line_number":294,"context_line":"                LOG.error("},{"line_number":295,"context_line":"                    \u0027Device %s: resource provider exists without \u0027"},{"line_number":296,"context_line":"                    \u0027OWNER_CYBORG trait; skipping.\u0027,"}],"source_content_type":"text/x-python","patch_set":7,"id":"44b59116_4b7df80e","line":293,"updated":"2026-08-09 05:13:18.000000000","message":"NVMeDriver.discover() calls _rp_exists_without_owner_cyborg() for each NVMe device, which makes two HTTP round-trips to Placement (resource_providers lookup + traits lookup). Because ResourceTracker.update_usage() calls discover() on every periodic refresh, this results in 2*N Placement HTTP call...\n\n**Severity**: WARNING | **Confidence**: 0.8\n\n**Impact**: On a compute host with multiple NVMe devices, every periodic interval generates unnecessary Placement API traffic. At scale this adds load to the Placement service and increases agent startup/refresh latency.\n\n**Suggestion**:\nConsider caching the OWNER_CYBORG check result per device, adding a flag to skip the Placement check when discover() is called from the periodic path, or moving the ownership check to init_host/startup only rather than every discover() call.","commit_id":"c1d148aa055ad4f431daff8a3111d2b59cdb0f0f"},{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"269aadf8fb60e2ab2db41ef226e697c7c8a09408","unresolved":false,"context_lines":[{"line_number":84,"context_line":"                    put_resp \u003d client.put("},{"line_number":85,"context_line":"                        \u0027/traits/%s\u0027 % trait, None, version\u003d\u00271.6\u0027"},{"line_number":86,"context_line":"                    )"},{"line_number":87,"context_line":"                    if put_resp.status_code !\u003d 201:"},{"line_number":88,"context_line":"                        raise exception.InvalidConfiguration("},{"line_number":89,"context_line":"                            reason\u003d("},{"line_number":90,"context_line":"                                \u0027Failed to register NVMe trait %s in \u0027"}],"source_content_type":"text/x-python","patch_set":8,"id":"1b992578_a2642de0","line":87,"updated":"2026-08-11 09:34:14.000000000","message":"The trait-registration code does GET /traits/{name}; if 404, it PUTs the trait and requires status 201. However, Placement\u0027s PUT /traits/{name} returns 200 OK when the trait already exists and 201 Created when newly created. If another agent or process creates the same trait between the GET (404)...\n\n**Severity**: HIGH | **Confidence**: 0.8\n\n**Risk**: In a multi-agent deployment where two agents start concurrently (e.g., after a cluster-wide restart), one agent\u0027s GET may return 404 while the other has already PUT the trait. The second PUT returns 200, raising InvalidConfiguration and crashing the agent. This is intermittent and depends on timing.\n\n**Priority**: Before merge\n**Why This Matters**: In a multi-agent deployment where two agents start concurrently (e.g., after a cluster-wide restart), one agent\u0027s GET may return 404 while the other has already PUT the trait. The second PUT returns 200, raising InvalidConfiguration and crashing the agent. This is intermittent and depends on timing.\n\n**Recommendation**:\nAccept both 200 and 201 as success: change the check to `if put_resp.status_code not in (200, 201):`. Alternatively, skip the GET check entirely and just PUT (idempotent), accepting 200 or 201.","commit_id":"025c61667ca956836966b60c97274d59276a0aa3"},{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"269aadf8fb60e2ab2db41ef226e697c7c8a09408","unresolved":false,"context_lines":[{"line_number":225,"context_line":"            )"},{"line_number":226,"context_line":"            return False"},{"line_number":227,"context_line":""},{"line_number":228,"context_line":"    def _build_traits(self, caps):"},{"line_number":229,"context_line":"        traits \u003d [constants.OWNER_CYBORG]"},{"line_number":230,"context_line":"        if caps[\u0027ces\u0027]:"},{"line_number":231,"context_line":"            traits.append(TRAIT_HW_NVME_CES)"}],"source_content_type":"text/x-python","patch_set":8,"id":"bca2ce4f_70495b72","line":228,"updated":"2026-08-11 09:34:14.000000000","message":"The NVMe driver defines _build_traits twice. The first (line 184) accepts (self, caps, vendor_id, product_id) and emits CUSTOM_NVME_PRODUCT_ID_\u003cpid\u003e. The second (line 228) accepts only (self, caps). Python uses the second, silently overriding the first. discover() calls self._build_traits(caps, v...\n\n**Severity**: CRITICAL | **Confidence**: 1.0\n\n**Risk**: discover() is completely non-functional - every call raises TypeError before any device is returned. The CUSTOM_NVME_PRODUCT_ID_\u003cpid\u003e trait is never emitted, so device profiles that require it cannot be satisfied by the scheduler, producing \u0027No valid host was found\u0027 for all NVMe lifecycle tests a...\n\n**Priority**: Immediate\n**Why This Matters**: discover() is completely non-functional - every call raises TypeError before any device is returned. The CUSTOM_NVME_PRODUCT_ID_\u003cpid\u003e trait is never emitted, so device profiles that require it cannot be satisfied by the scheduler, producing \u0027No valid host was found\u0027 for all NVMe lifecycle tests a...\n\n**Recommendation**:\nDelete the second _build_traits definition at line 228-236. The first definition (line 184-194) is the correct one that accepts vendor_id/product_id and emits the product-id trait.","commit_id":"025c61667ca956836966b60c97274d59276a0aa3"},{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"1ebc13b6c260dbf263540e6b6d611ec154de7d22","unresolved":false,"context_lines":[{"line_number":182,"context_line":""},{"line_number":183,"context_line":"        return None"},{"line_number":184,"context_line":""},{"line_number":185,"context_line":"    def _build_traits(self, caps):"},{"line_number":186,"context_line":"        traits \u003d [constants.OWNER_CYBORG]"},{"line_number":187,"context_line":"        if caps[\u0027ces\u0027]:"},{"line_number":188,"context_line":"            traits.append(TRAIT_HW_NVME_CES)"}],"source_content_type":"text/x-python","patch_set":10,"id":"2f3e5ee8_e6a56732","line":185,"updated":"2026-08-12 08:56:46.000000000","message":"The commit message explicitly states that _build_traits should accept vendor_id and product_id to emit a CUSTOM_NVME_PRODUCT_ID_\u003cpid\u003e trait, and that without it \u0027No valid host was found\u0027 for all NVMe lifecycle tests. However the actual _build_traits method only accepts caps and emits OWNER_CYBORG...\n\n**Severity**: HIGH | **Confidence**: 0.9\n\n**Risk**: Device profiles that require trait CUSTOM_NVME_PRODUCT_ID_\u003cpid\u003e (such as those created by the devstack fixture described in the commit message) will fail to match NVMe devices, resulting in \u0027No valid host was found\u0027 errors. This breaks the core use case described in the commit message.\n\n**Priority**: Before merge\n**Why This Matters**: Device profiles that require trait CUSTOM_NVME_PRODUCT_ID_\u003cpid\u003e (such as those created by the devstack fixture described in the commit message) will fail to match NVMe devices, resulting in \u0027No valid host was found\u0027 errors. This breaks the core use case described in the commit message.\n\n**Recommendation**:\nUpdate _build_traits to accept vendor_id and product_id parameters and emit a CUSTOM_NVME_PRODUCT_ID_\u003cpid\u003e trait, matching the pattern used by other Cyborg drivers. Update the call site at line 309 to pass vendor_id and product_id. Add a test assertion for the trait.","commit_id":"d09974242d75ead54403c47e2a7c830d2d7e3389"},{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"1ebc13b6c260dbf263540e6b6d611ec154de7d22","unresolved":false,"context_lines":[{"line_number":345,"context_line":"    def get_stats(self):"},{"line_number":346,"context_line":"        return {}"},{"line_number":347,"context_line":""},{"line_number":348,"context_line":"    def cleanup(self, device):"},{"line_number":349,"context_line":"        pass"}],"source_content_type":"text/x-python","patch_set":10,"id":"a7195987_98639e6d","line":348,"updated":"2026-08-12 08:56:46.000000000","message":"The release note states the driver \u0027supports post-teardown cleanup via NVMe sanitize (crypto-erase or block-erase) and write-zeroes, with configurable policy.\u0027 While the driver resolves a cleanup_action policy during discover() and stores it in std_board_info, the actual cleanup() method is an em...\n\n**Severity**: SUGGESTION | **Confidence**: 0.8\n\n**Benefit**: Operators reading the release note will expect NVMe sanitize/write-zeroes cleanup to function. The policy resolution and std_board_info storage give the appearance of a working feature, but no cleanup is ever executed. This could lead to devices being returned to the pool without data sanitization.\n\n**Recommendation**:\nEither implement cleanup() to execute the stored cleanup_action using the nvme_cli helper functions, or adjust the release note to clarify that cleanup execution is planned but not yet implemented in this release. At minimum, document the current limitation.","commit_id":"d09974242d75ead54403c47e2a7c830d2d7e3389"},{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"a016e687c14f6fcd7f4553653bf46cf1135eab29","unresolved":false,"context_lines":[{"line_number":54,"context_line":""},{"line_number":55,"context_line":"# os-traits companion change has not landed in requirements yet, so keep"},{"line_number":56,"context_line":"# the Placement trait names local to this driver for now."},{"line_number":57,"context_line":"TRAIT_HW_NVME_CES \u003d \u0027HW_NVME_CES\u0027"},{"line_number":58,"context_line":"TRAIT_HW_NVME_BES \u003d \u0027HW_NVME_BES\u0027"},{"line_number":59,"context_line":"TRAIT_HW_NVME_WZS \u003d \u0027HW_NVME_WZS\u0027"},{"line_number":60,"context_line":""}],"source_content_type":"text/x-python","patch_set":12,"id":"892540ee_30e98529","line":57,"updated":"2026-08-14 15:33:02.000000000","message":"_ensure_nvme_traits() PUTs traits named \u0027HW_NVME_CES\u0027/\u0027HW_NVME_BES\u0027/\u0027HW_NVME_WZS\u0027, but the Placement API requires custom trait names to start with CUSTOM_; a PUT /traits/HW_NVME_CES returns 400, which the code turns into a raised InvalidConfiguration and agent startup abort.\n\n**Severity**: HIGH | **Confidence**: 0.8\n\n**Risk**: With the NVMe driver enabled, agent startup hits the hard InvalidConfiguration path (400 !\u003d 201), reproducing the whole-agent outage of CF-003 even on a fully provisioned host with Placement healthy. Trait-based scheduling on the capability traits also cannot work.\n\n**Priority**: Before merge\n**Why This Matters**: With the NVMe driver enabled, agent startup hits the hard InvalidConfiguration path (400 !\u003d 201), reproducing the whole-agent outage of CF-003 even on a fully provisioned host with Placement healthy. Trait-based scheduling on the capability traits also cannot work.\n\n**Recommendation**:\nRename the constants to CUSTOM_HW_NVME_* (or adopt standard os-traits names once available and rely on Placement already knowing them), and adjust the tests and _build_traits output consistently.","commit_id":"d0ed397ba88c229ca4f0746f113bb90851a0fd88"},{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"a016e687c14f6fcd7f4553653bf46cf1135eab29","unresolved":false,"context_lines":[{"line_number":182,"context_line":""},{"line_number":183,"context_line":"        return None"},{"line_number":184,"context_line":""},{"line_number":185,"context_line":"    def _build_traits(self, caps):"},{"line_number":186,"context_line":"        traits \u003d [constants.OWNER_CYBORG]"},{"line_number":187,"context_line":"        if caps[\u0027ces\u0027]:"},{"line_number":188,"context_line":"            traits.append(TRAIT_HW_NVME_CES)"}],"source_content_type":"text/x-python","patch_set":12,"id":"fdba0f29_7d29d38e","line":185,"updated":"2026-08-14 15:33:02.000000000","message":"The commit message and release note state that _build_traits emits CUSTOM_NVME_PRODUCT_ID_\u003cpid\u003e so devstack device profiles requiring that trait can be satisfied, but _build_traits() only ever emits OWNER_CYBORG plus the three HW_NVME_* capability traits.\n\n**Severity**: HIGH | **Confidence**: 0.9\n\n**Risk**: Any device profile requiring CUSTOM_NVME_PRODUCT_ID_\u003cpid\u003e (per the commit message, the devstack fixture profiles) will not match any NVMe deployable at scheduling time, causing \u0027No valid host was found\u0027 for NVMe lifecycle flows despite discovery succeeding.\n\n**Priority**: Before merge\n**Why This Matters**: Any device profile requiring CUSTOM_NVME_PRODUCT_ID_\u003cpid\u003e (per the commit message, the devstack fixture profiles) will not match any NVMe deployable at scheduling time, causing \u0027No valid host was found\u0027 for NVMe lifecycle flows despite discovery succeeding.\n\n**Recommendation**:\nEither accept vendor_id/product_id in _build_traits and append \u0027CUSTOM_NVME_PRODUCT_ID_%s\u0027 % product_id.upper() (mirroring the inspur/xilinx FPGA drivers) with a matching test, or update the commit message/release note and devstack fixture so the documented contract matches the code.","commit_id":"d0ed397ba88c229ca4f0746f113bb90851a0fd88"},{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"a016e687c14f6fcd7f4553653bf46cf1135eab29","unresolved":false,"context_lines":[{"line_number":345,"context_line":"    def get_stats(self):"},{"line_number":346,"context_line":"        return {}"},{"line_number":347,"context_line":""},{"line_number":348,"context_line":"    def cleanup(self, device):"},{"line_number":349,"context_line":"        pass"}],"source_content_type":"text/x-python","patch_set":12,"id":"d0816a01_2a87d41d","line":348,"updated":"2026-08-14 15:33:02.000000000","message":"The entire policy matrix, cleanup_action preservation logic, and the \u0027requires cleanup-policy resolution before safe allocation\u0027 rationale of this patch revolve around NVMe sanitize/write-zeroes, yet NVMeDriver.cleanup() does nothing and nothing else in the tree calls nvme_cli.nvme_sanitize or nv...\n\n**Severity**: HIGH | **Confidence**: 0.8\n\n**Risk**: Deallocated NVMe devices are returned to the pool without any data sanitization while the release note tells operators sanitization is performed - a data-hygiene gap and misleading operator documentation.\n\n**Priority**: Before merge\n**Why This Matters**: Deallocated NVMe devices are returned to the pool without any data sanitization while the release note tells operators sanitization is performed - a data-hygiene gap and misleading operator documentation.\n\n**Recommendation**:\nImplement cleanup() to dispatch on std_board_info cleanup_action to nvme_sanitize or nvme_write_zeroes (returning a pending/deferred status where sanitize is asynchronous), or land it in a fast-follow patch and remove the cleanup claim from this release note until it exists.","commit_id":"d0ed397ba88c229ca4f0746f113bb90851a0fd88"}],"cyborg/agent/manager.py":[{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"a016e687c14f6fcd7f4553653bf46cf1135eab29","unresolved":false,"context_lines":[{"line_number":97,"context_line":"        self.image_api \u003d ImageAPI()"},{"line_number":98,"context_line":"        self._rt \u003d ResourceTracker(self.resource_provider_name, self.cond_api)"},{"line_number":99,"context_line":""},{"line_number":100,"context_line":"    def init_host(self):"},{"line_number":101,"context_line":"        \"\"\"Hook called by RPCService.start() after the RPC server is up.\"\"\""},{"line_number":102,"context_line":"        self._rt.init_drivers()"},{"line_number":103,"context_line":"        all_devices \u003d self._rt.discover_all()"}],"source_content_type":"text/x-python","patch_set":12,"id":"a8e2b008_50560c96","line":100,"updated":"2026-08-14 15:33:02.000000000","message":"AgentManager.init_host() now calls init_drivers(), which propagates driver exceptions (e.g. InvalidConfiguration when nvme-cli is missing, per the new resource_tracker test test_init_drivers_propagates_exception). RPCService.start() hooks do not retry, so an agent missing nvme-cli enters a restar...\n\n**Severity**: HIGH | **Confidence**: 0.8\n\n**Risk**: On a host where the NVMe driver is enabled but nvme-cli is not installed (a common ordering gap during upgrades, acknowledged in the release note), the cyborg-agent crashes at startup, loops, and stops reporting all accelerator resources - not just NVMe - to conductor and Placement.\n\n**Priority**: Before merge\n**Why This Matters**: On a host where the NVMe driver is enabled but nvme-cli is not installed (a common ordering gap during upgrades, acknowledged in the release note), the cyborg-agent crashes at startup, loops, and stops reporting all accelerator resources - not just NVMe - to conductor and Placement.\n\n**Recommendation**:\nCatch per-driver exceptions in ResourceTracker.init_drivers(), LOG.exception and disable/skip that driver (matching how _initialize_drivers already tolerates unusable drivers), so one driver\u0027s missing prerequisite does not take down the whole agent; alternatively gate NVMeDriver loading on [nvme] device_spec being configured.","commit_id":"d0ed397ba88c229ca4f0746f113bb90851a0fd88"}],"cyborg/agent/resource_tracker.py":[{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"314095d6a6a7b3672f6d2c2ee4a2c498d9737177","unresolved":false,"context_lines":[{"line_number":72,"context_line":"            LOG.info(\u0027Calling init_host() for driver %s\u0027, name)"},{"line_number":73,"context_line":"            drv.init_host()"},{"line_number":74,"context_line":""},{"line_number":75,"context_line":"    def check_duplicate_devices(self):"},{"line_number":76,"context_line":"        seen \u003d {}"},{"line_number":77,"context_line":"        for name, drv in self.acc_drivers.items():"},{"line_number":78,"context_line":"            devices \u003d drv.discover()"}],"source_content_type":"text/x-python","patch_set":6,"id":"699fd661_2872e8ce","line":75,"updated":"2026-08-07 16:26:37.000000000","message":"ResourceTracker.check_duplicate_devices() (new in this patch) calls drv.discover() on every loaded driver. ResourceTracker.update_usage() also calls drv.discover(). For NVMeDriver, discover() invokes nvme-cli subprocesses (resolve_nvme_dev_from_pci and nvme_id_ctrl) for each device. At agent star...\n\n**Severity**: WARNING | **Confidence**: 0.8\n\n**Impact**: On hosts with multiple NVMe devices, startup latency doubles due to redundant nvme-cli invocations. Each subprocess call runs under sys_admin privsep context, adding overhead. While not a correctness bug, this is wasteful for a production service startup path.\n\n**Suggestion**:\nConsider caching the discover() results from check_duplicate_devices() and reusing them for the initial update_usage() call, or moving the duplicate check to operate on cached device data rather than calling discover() again.","commit_id":"de95d37c8b7853605419d0930962b42e7c6fb9cc"},{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"f26c2dd98eaebbeec53a85fff33719bae590e348","unresolved":false,"context_lines":[{"line_number":67,"context_line":"            acc_drivers[d] \u003d acc_driver"},{"line_number":68,"context_line":"        self.acc_drivers \u003d acc_drivers"},{"line_number":69,"context_line":""},{"line_number":70,"context_line":"    def init_drivers(self):"},{"line_number":71,"context_line":"        for name, drv in self.acc_drivers.items():"},{"line_number":72,"context_line":"            LOG.info(\u0027Calling init_host() for driver %s\u0027, name)"},{"line_number":73,"context_line":"            drv.init_host()"}],"source_content_type":"text/x-python","patch_set":9,"id":"5a9f9ae3_0c38c3b2","line":70,"updated":"2026-08-11 15:21:10.000000000","message":"init_drivers() iterates all enabled drivers calling init_host() without isolating per-driver failures. If the NVMe driver\u0027s init_host() raises InvalidConfiguration (e.g. nvme-cli not installed), the exception propagates up through init_host() and prevents the agent from starting even for non-NVMe...\n\n**Severity**: HIGH | **Confidence**: 0.8\n\n**Risk**: If any single driver fails init_host() (e.g. nvme-cli missing on a host that also has GPUs), the entire cyborg-agent service will fail to start, blocking all accelerator management for that host.\n\n**Priority**: Before merge\n**Why This Matters**: If any single driver fails init_host() (e.g. nvme-cli missing on a host that also has GPUs), the entire cyborg-agent service will fail to start, blocking all accelerator management for that host.\n\n**Recommendation**:\nWrap each driver\u0027s init_host() call in a try/except that logs the error and either skips the failed driver or marks it as unavailable, allowing other drivers to proceed. Consider whether a failed driver should be removed from acc_drivers before discover_all() runs.","commit_id":"0ece3d90c95e271c9875fb6bb92b80e60d738c22"}],"cyborg/conductor/manager.py":[{"author":{"_account_id":22348,"name":"Zuul","username":"zuul","tags":["SERVICE_USER"]},"tag":"autogenerated:zuul:check","change_message_id":"38c215fa903fca02d31e697ca060b4188d74ad03","unresolved":false,"context_lines":[{"line_number":243,"context_line":"                cpid_info \u003d new_driver_dev_obj.controlpath_id.cpid_info"},{"line_number":244,"context_line":"                dev_obj \u003d self._find_device_by_cpid(context, host, cpid_info)"},{"line_number":245,"context_line":"                if dev_obj is not None and dev_obj.device_state is None:"},{"line_number":246,"context_line":"                    dev_obj.device_state \u003d constants.DEVICE_STATE_AVAILABLE"},{"line_number":247,"context_line":"                    dev_obj.save(context)"},{"line_number":248,"context_line":"        for s in same:"},{"line_number":249,"context_line":"            # get the driver_dev_obj, diff the driver_device layer"}],"source_content_type":"text/x-python","patch_set":6,"id":"c63663d6_e027295c","line":246,"updated":"2026-08-07 17:19:25.000000000","message":"pep8: F821 Undefined name `constants`","commit_id":"de95d37c8b7853605419d0930962b42e7c6fb9cc"},{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"314095d6a6a7b3672f6d2c2ee4a2c498d9737177","unresolved":false,"context_lines":[{"line_number":550,"context_line":"                    break"},{"line_number":551,"context_line":""},{"line_number":552,"context_line":""},{"line_number":553,"context_line":"_NVME_CLEANUP_LOCKED_STATES \u003d frozenset(["},{"line_number":554,"context_line":"    constants.DEVICE_STATE_ALLOCATED,"},{"line_number":555,"context_line":"    constants.DEVICE_STATE_PENDING_CLEANING,"},{"line_number":556,"context_line":"    constants.DEVICE_STATE_CLEANING,"}],"source_content_type":"text/x-python","patch_set":6,"id":"b9d032a0_5a6fc275","line":553,"updated":"2026-08-07 16:26:37.000000000","message":"The patch adds references to constants.DEVICE_STATE_AVAILABLE (line 246) and constants.DEVICE_STATE_ALLOCATED/PENDING_CLEANING/CLEANING (lines 554-556) in conductor/manager.py, but never imports the constants module. The _NVME_CLEANUP_LOCKED_STATES frozenset is evaluated at module import time, so...\n\n**Severity**: CRITICAL | **Confidence**: 1.0\n\n**Risk**: The cyborg-conductor service will fail to start with an unhandled NameError. Additionally, any unit test that imports cyborg.conductor.manager will fail at collection time, potentially masking other test failures. This is a merge-blocking defect.\n\n**Priority**: Immediate\n**Why This Matters**: The cyborg-conductor service will fail to start with an unhandled NameError. Additionally, any unit test that imports cyborg.conductor.manager will fail at collection time, potentially masking other test failures. This is a merge-blocking defect.\n\n**Recommendation**:\nAdd \u0027from cyborg.common import constants\u0027 to the import block in cyborg/conductor/manager.py, alongside the existing \u0027from cyborg.common import data_migrations\u0027 and \u0027from cyborg.common import exception\u0027 imports.","commit_id":"de95d37c8b7853605419d0930962b42e7c6fb9cc"},{"author":{"_account_id":22348,"name":"Zuul","username":"zuul","tags":["SERVICE_USER"]},"tag":"autogenerated:zuul:check","change_message_id":"38c215fa903fca02d31e697ca060b4188d74ad03","unresolved":false,"context_lines":[{"line_number":551,"context_line":""},{"line_number":552,"context_line":""},{"line_number":553,"context_line":"_NVME_CLEANUP_LOCKED_STATES \u003d frozenset(["},{"line_number":554,"context_line":"    constants.DEVICE_STATE_ALLOCATED,"},{"line_number":555,"context_line":"    constants.DEVICE_STATE_PENDING_CLEANING,"},{"line_number":556,"context_line":"    constants.DEVICE_STATE_CLEANING,"},{"line_number":557,"context_line":"])"}],"source_content_type":"text/x-python","patch_set":6,"id":"fa52e5c2_f7da7998","line":554,"updated":"2026-08-07 17:19:25.000000000","message":"pep8: F821 Undefined name `constants`","commit_id":"de95d37c8b7853605419d0930962b42e7c6fb9cc"},{"author":{"_account_id":22348,"name":"Zuul","username":"zuul","tags":["SERVICE_USER"]},"tag":"autogenerated:zuul:check","change_message_id":"38c215fa903fca02d31e697ca060b4188d74ad03","unresolved":false,"context_lines":[{"line_number":552,"context_line":""},{"line_number":553,"context_line":"_NVME_CLEANUP_LOCKED_STATES \u003d frozenset(["},{"line_number":554,"context_line":"    constants.DEVICE_STATE_ALLOCATED,"},{"line_number":555,"context_line":"    constants.DEVICE_STATE_PENDING_CLEANING,"},{"line_number":556,"context_line":"    constants.DEVICE_STATE_CLEANING,"},{"line_number":557,"context_line":"])"},{"line_number":558,"context_line":""}],"source_content_type":"text/x-python","patch_set":6,"id":"d24b0d7b_8fd38c00","line":555,"updated":"2026-08-07 17:19:25.000000000","message":"pep8: F821 Undefined name `constants`","commit_id":"de95d37c8b7853605419d0930962b42e7c6fb9cc"},{"author":{"_account_id":22348,"name":"Zuul","username":"zuul","tags":["SERVICE_USER"]},"tag":"autogenerated:zuul:check","change_message_id":"38c215fa903fca02d31e697ca060b4188d74ad03","unresolved":false,"context_lines":[{"line_number":553,"context_line":"_NVME_CLEANUP_LOCKED_STATES \u003d frozenset(["},{"line_number":554,"context_line":"    constants.DEVICE_STATE_ALLOCATED,"},{"line_number":555,"context_line":"    constants.DEVICE_STATE_PENDING_CLEANING,"},{"line_number":556,"context_line":"    constants.DEVICE_STATE_CLEANING,"},{"line_number":557,"context_line":"])"},{"line_number":558,"context_line":""},{"line_number":559,"context_line":""}],"source_content_type":"text/x-python","patch_set":6,"id":"9f2b8ae9_7cb2fe38","line":556,"updated":"2026-08-07 17:19:25.000000000","message":"pep8: F821 Undefined name `constants`","commit_id":"de95d37c8b7853605419d0930962b42e7c6fb9cc"},{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"269aadf8fb60e2ab2db41ef226e697c7c8a09408","unresolved":false,"context_lines":[{"line_number":275,"context_line":"                old_val \u003d getattr(old_driver_dev_obj, c_k)"},{"line_number":276,"context_line":"                if new_val \u003d\u003d old_val:"},{"line_number":277,"context_line":"                    continue"},{"line_number":278,"context_line":"                if c_k \u003d\u003d \u0027std_board_info\u0027 and dev_obj.type \u003d\u003d \u0027NVME\u0027:"},{"line_number":279,"context_line":"                    new_val \u003d _merge_nvme_board_info("},{"line_number":280,"context_line":"                        old_val, new_val, dev_obj.device_state"},{"line_number":281,"context_line":"                    )"}],"source_content_type":"text/x-python","patch_set":8,"id":"4b3491aa_6d5d8ba4","line":278,"updated":"2026-08-11 09:34:14.000000000","message":"The conductor manager uses a hardcoded string literal \u0027NVME\u0027 to check the device type before merging board info, despite the constants module defining DEVICE_NVME \u003d \u0027NVME\u0027 and the constants module already being imported in this file.\n\n**Severity**: SUGGESTION | **Confidence**: 0.9\n\n**Benefit**: If the DEVICE_NVME constant value ever changes or the string is mistyped, the merge logic silently fails to trigger, potentially overwriting cleanup_action during in-flight sanitize operations. Low probability but directly actionable.\n\n**Recommendation**:\nReplace \u0027NVME\u0027 with constants.DEVICE_NVME: `if c_k \u003d\u003d \u0027std_board_info\u0027 and dev_obj.type \u003d\u003d constants.DEVICE_NVME:`","commit_id":"025c61667ca956836966b60c97274d59276a0aa3"},{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"f26c2dd98eaebbeec53a85fff33719bae590e348","unresolved":false,"context_lines":[{"line_number":275,"context_line":"                old_val \u003d getattr(old_driver_dev_obj, c_k)"},{"line_number":276,"context_line":"                if new_val \u003d\u003d old_val:"},{"line_number":277,"context_line":"                    continue"},{"line_number":278,"context_line":"                if c_k \u003d\u003d \u0027std_board_info\u0027 and dev_obj.type \u003d\u003d \u0027NVME\u0027:"},{"line_number":279,"context_line":"                    new_val \u003d _merge_nvme_board_info("},{"line_number":280,"context_line":"                        old_val, new_val, dev_obj.device_state"},{"line_number":281,"context_line":"                    )"}],"source_content_type":"text/x-python","patch_set":9,"id":"913c4941_d44c80c4","line":278,"updated":"2026-08-11 15:21:10.000000000","message":"In drv_device_make_diff(), the NVMe board info merge condition uses a hardcoded string literal \u0027NVME\u0027 to compare against dev_obj.type, while the rest of the codebase consistently uses constants.DEVICE_NVME for this comparison.\n\n**Severity**: SUGGESTION | **Confidence**: 0.9\n\n**Benefit**: If DEVICE_NVME is ever renamed or the value changes, this comparison will silently break, causing the merge logic to be skipped for all NVMe devices.\n\n**Recommendation**:\nReplace \u0027NVME\u0027 with constants.DEVICE_NVME (constants is already imported in this file).","commit_id":"0ece3d90c95e271c9875fb6bb92b80e60d738c22"},{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"75490aa828304f0778f4426ab19da1bbe4cb5f6f","unresolved":false,"context_lines":[{"line_number":275,"context_line":"                old_val \u003d getattr(old_driver_dev_obj, c_k)"},{"line_number":276,"context_line":"                if new_val \u003d\u003d old_val:"},{"line_number":277,"context_line":"                    continue"},{"line_number":278,"context_line":"                if c_k \u003d\u003d \u0027std_board_info\u0027 and dev_obj.type \u003d\u003d \u0027NVME\u0027:"},{"line_number":279,"context_line":"                    new_val \u003d _merge_nvme_board_info("},{"line_number":280,"context_line":"                        old_val, new_val, dev_obj.device_state"},{"line_number":281,"context_line":"                    )"}],"source_content_type":"text/x-python","patch_set":11,"id":"c28f5aa6_df78be2e","line":278,"updated":"2026-08-13 04:59:07.000000000","message":"The _merge_nvme_board_info dispatch in drv_device_make_diff uses a hardcoded string \u0027NVME\u0027 for the device type check instead of the existing constants.DEVICE_NVME constant, which is already imported and used elsewhere in the same file.\n\n**Severity**: SUGGESTION | **Confidence**: 0.9\n\n**Benefit**: Minor maintainability risk: if the DEVICE_NVME constant value ever changes, this comparison would silently break. Using the constant is the established pattern in this file.\n\n**Recommendation**:\nReplace the hardcoded \u0027NVME\u0027 with constants.DEVICE_NVME for consistency with the rest of the file and the constants module.","commit_id":"2fb1b5b4e81d79f57ff110dc1b4926ab784c1f40"}],"cyborg/tests/unit/accelerator/drivers/nvme/test_driver.py":[{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"6f6d87758d679a0776bac9db7b8314c6d03ded16","unresolved":false,"context_lines":[{"line_number":64,"context_line":"class TestNVMeDriverDiscover(base.TestCase):"},{"line_number":65,"context_line":"    @mock.patch.object(nvme_cli, \u0027nvme_id_ctrl\u0027)"},{"line_number":66,"context_line":"    @mock.patch.object(nvme_cli, \u0027resolve_nvme_dev_from_pci\u0027)"},{"line_number":67,"context_line":"    def test_single_device(self, mock_resolve, mock_id):"},{"line_number":68,"context_line":"        mock_resolve.return_value \u003d \u0027/dev/nvme0\u0027"},{"line_number":69,"context_line":"        mock_id.return_value \u003d {"},{"line_number":70,"context_line":"            \u0027sanicap\u0027: 3,"}],"source_content_type":"text/x-python","patch_set":7,"id":"a3070226_56a542c8","line":67,"updated":"2026-08-09 05:13:18.000000000","message":"test_single_device calls NVMeDriver(pci_sysfs_path\u003dtmp).discover() without mocking _rp_exists_without_owner_cyborg or PlacementClient. The test passes only because _rp_exists_without_owner_cyborg has a broad except Exception that returns False when the real PlacementClient cannot connect. This ma...\n\n**Severity**: WARNING | **Confidence**: 0.8\n\n**Impact**: The test could behave differently depending on the CI/network environment. If PlacementClient is ever stubbed at a higher level, or if a network call somehow succeeds and returns unexpected data, the test may fail or pass for the wrong reason. The test may also add unnecessary latency due to conn...\n\n**Suggestion**:\nAdd @mock.patch.object(NVMeDriver, \u0027_rp_exists_without_owner_cyborg\u0027, return_value\u003dFalse) to test_single_device (and other discover tests that exercise the full flow) to explicitly control the Placement check outcome.","commit_id":"c1d148aa055ad4f431daff8a3111d2b59cdb0f0f"},{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"a016e687c14f6fcd7f4553653bf46cf1135eab29","unresolved":false,"context_lines":[{"line_number":54,"context_line":"        NVMeDriver().init_host()"},{"line_number":55,"context_line":""},{"line_number":56,"context_line":"    @mock.patch(\u0027shutil.which\u0027, return_value\u003dNone)"},{"line_number":57,"context_line":"    def test_raises(self, mock_which):"},{"line_number":58,"context_line":"        self.assertRaises("},{"line_number":59,"context_line":"            exception.InvalidConfiguration,"},{"line_number":60,"context_line":"            NVMeDriver().init_host,"}],"source_content_type":"text/x-python","patch_set":12,"id":"9ebca73b_4c448b67","line":57,"updated":"2026-08-14 15:33:02.000000000","message":"TestNVMeDriverInitHost only mocks shutil.which; the Placement trait-registration logic (404-then-PUT flow, non-201 raising InvalidConfiguration, soft-fail on unreachable Placement) has zero coverage.\n\n**Severity**: WARNING | **Confidence**: 0.9\n\n**Impact**: Placement contract violations such as the CUSTOM_ prefix problem ship undetected; regressions in the soft-fail behavior would also go unnoticed.\n\n**Suggestion**:\nAdd tests with a mocked placement client covering: trait already exists (200), trait created (404 then PUT 201), PUT failure raising InvalidConfiguration, and transport error falling through to LOG.warning without raising.","commit_id":"d0ed397ba88c229ca4f0746f113bb90851a0fd88"}],"cyborg/tests/unit/agent/test_manager.py":[{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"6f6d87758d679a0776bac9db7b8314c6d03ded16","unresolved":false,"context_lines":[{"line_number":232,"context_line":"            self._create_manager_with_mocks,"},{"line_number":233,"context_line":"        )"},{"line_number":234,"context_line":""},{"line_number":235,"context_line":"    def test_init_host_calls_rt(self):"},{"line_number":236,"context_line":"        self.placement_mock.get.return_value.json.return_value \u003d {"},{"line_number":237,"context_line":"            \u0027resource_providers\u0027: [{\u0027uuid\u0027: \u0027test-uuid\u0027}]"},{"line_number":238,"context_line":"        }"}],"source_content_type":"text/x-python","patch_set":7,"id":"6e6df934_4d3e2242","line":235,"updated":"2026-08-09 05:13:18.000000000","message":"AgentManager.init_host() calls three methods: init_drivers(), discover_all(), and check_duplicate_devices(all_devices). The test asserts init_drivers and check_duplicate_devices are called but does not verify discover_all() is called, leaving the middle step of the startup sequence unverified.\n\n**Severity**: SUGGESTION | **Confidence**: 0.9\n\n**Benefit**: If discover_all() is accidentally removed from init_host(), the test would still pass because check_duplicate_devices receives a Mock return value from the mocked _rt. The test does not guard against regression of the discover_all call.\n\n**Recommendation**:\nAdd am._rt.discover_all.assert_called_once() after the existing assertions in test_init_host_calls_rt.","commit_id":"c1d148aa055ad4f431daff8a3111d2b59cdb0f0f"}],"cyborg/tests/unit/conductor/test_manager.py":[{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"314095d6a6a7b3672f6d2c2ee4a2c498d9737177","unresolved":false,"context_lines":[{"line_number":223,"context_line":"        self.cm.init_host()"},{"line_number":224,"context_line":"        mock_heal.assert_called_once()"},{"line_number":225,"context_line":""},{"line_number":226,"context_line":"    @mock.patch(\u0027cyborg.conductor.manager.ConductorManager._find_device_by_cpid\u0027)"},{"line_number":227,"context_line":"    @mock.patch(\u0027cyborg.conductor.manager.ConductorManager.drv_device_make_diff\u0027)"},{"line_number":228,"context_line":"    def test_new_nvme_device_initialized_as_available("},{"line_number":229,"context_line":"        self, mock_diff, mock_find_cpid"}],"source_content_type":"text/x-python","patch_set":6,"id":"6340a1df_bd3fdf9d","line":226,"updated":"2026-08-07 16:26:37.000000000","message":"The test named test_new_nvme_device_initialized_as_available mocks _find_device_by_cpid, then calls the mocked _find_device_by_cpid directly. It never invokes drv_device_make_diff, which is the method containing the actual device_state initialization logic (lines 243-247). The test only verifies...\n\n**Severity**: HIGH | **Confidence**: 0.9\n\n**Risk**: A reviewer seeing this test pass would believe the NVMe device-state initialization is verified. In reality, the critical logic that sets device_state to DEVICE_STATE_AVAILABLE for newly discovered NVMe devices is untested and could silently break.\n\n**Priority**: Before merge\n**Why This Matters**: A reviewer seeing this test pass would believe the NVMe device-state initialization is verified. In reality, the critical logic that sets device_state to DEVICE_STATE_AVAILABLE for newly discovered NVMe devices is untested and could silently break.\n\n**Recommendation**:\nRewrite the test to call drv_device_make_diff with appropriate fake driver device objects, and assert that the resulting dev_obj.device_state equals constants.DEVICE_STATE_AVAILABLE and that dev_obj.save() was called. Do not mock _find_device_by_cpid; instead mock Device.get_list_by_hostname and ControlpathID.get_by_device_id_cpidinfo to return the needed objects.","commit_id":"de95d37c8b7853605419d0930962b42e7c6fb9cc"},{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"314095d6a6a7b3672f6d2c2ee4a2c498d9737177","unresolved":false,"context_lines":[{"line_number":249,"context_line":"        old \u003d \u0027{\"cleanup_action\": \"sanitize_ces\", \"nvme_dev\": \"/dev/nvme0\"}\u0027"},{"line_number":250,"context_line":"        new \u003d \u0027{\"cleanup_action\": \"zero_wz\", \"nvme_dev\": \"/dev/nvme0\"}\u0027"},{"line_number":251,"context_line":"        result \u003d self._merge(old, new, \u0027allocated\u0027)"},{"line_number":252,"context_line":"        import json"},{"line_number":253,"context_line":"        self.assertEqual(\u0027sanitize_ces\u0027, json.loads(result)[\u0027cleanup_action\u0027])"},{"line_number":254,"context_line":""},{"line_number":255,"context_line":"    def test_preserves_action_in_pending_cleaning(self):"}],"source_content_type":"text/x-python","patch_set":6,"id":"803fceb4_c30d5245","line":252,"updated":"2026-08-07 16:26:37.000000000","message":"The TestMergeNVMeBoardInfo test class has \u0027import json\u0027 inside each of its 6 test methods (lines 252, 259, 266, 273, 280, 287) rather than a single import at the top of the test module. This is unconventional and makes the tests harder to maintain.\n\n**Severity**: SUGGESTION | **Confidence**: 0.9\n\n**Benefit**: Minor maintainability concern. The repeated inline import adds visual noise and inconsistency with the rest of the cyborg codebase which uses oslo_serialization.jsonutils. Not a correctness issue.\n\n**Recommendation**:\nMove \u0027import json\u0027 to the top of the test module, or better, use jsonutils.loads() which is already available from the existing oslo_serialization import, consistent with the rest of the cyborg codebase.","commit_id":"de95d37c8b7853605419d0930962b42e7c6fb9cc"},{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"6f6d87758d679a0776bac9db7b8314c6d03ded16","unresolved":false,"context_lines":[{"line_number":229,"context_line":"    @mock.patch("},{"line_number":230,"context_line":"        \u0027cyborg.conductor.manager.ConductorManager.drv_device_make_diff\u0027"},{"line_number":231,"context_line":"    )"},{"line_number":232,"context_line":"    def test_new_nvme_device_initialized_as_available("},{"line_number":233,"context_line":"        self, mock_diff, mock_find_cpid"},{"line_number":234,"context_line":"    ):"},{"line_number":235,"context_line":"        dev_obj \u003d mock.Mock()"}],"source_content_type":"text/x-python","patch_set":7,"id":"667f303f_b049e3a5","line":232,"updated":"2026-08-09 05:13:18.000000000","message":"The test named test_new_nvme_device_initialized_as_available calls _find_device_by_cpid directly (which is already mocked) and only asserts it was called once. It never invokes drv_device_make_diff or report_data, so the code path that sets device_state to DEVICE_STATE_AVAILABLE for newly added N...\n\n**Severity**: WARNING | **Confidence**: 0.9\n\n**Impact**: A reviewer relying on this test name for coverage of the NVMe device-state initialization path would have false confidence. Regression in the initialization logic could go undetected.\n\n**Suggestion**:\nRewrite the test to call report_data or drv_device_make_diff with a new device (not in old list), mock _find_device_by_cpid to return a dev_obj with device_state\u003dNone, and assert that dev_obj.device_state is set to constants.DEVICE_STATE_AVAILABLE and that dev_obj.save was called.","commit_id":"c1d148aa055ad4f431daff8a3111d2b59cdb0f0f"},{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"f26c2dd98eaebbeec53a85fff33719bae590e348","unresolved":false,"context_lines":[{"line_number":267,"context_line":"        old \u003d \u0027{\"cleanup_action\": \"sanitize_ces\", \"nvme_dev\": \"/dev/nvme0\"}\u0027"},{"line_number":268,"context_line":"        new \u003d \u0027{\"cleanup_action\": \"zero_wz\", \"nvme_dev\": \"/dev/nvme0\"}\u0027"},{"line_number":269,"context_line":"        result \u003d self._merge(old, new, \u0027allocated\u0027)"},{"line_number":270,"context_line":"        import json"},{"line_number":271,"context_line":""},{"line_number":272,"context_line":"        self.assertEqual(\u0027sanitize_ces\u0027, json.loads(result)[\u0027cleanup_action\u0027])"},{"line_number":273,"context_line":""}],"source_content_type":"text/x-python","patch_set":9,"id":"ac228d3c_6032fc74","line":270,"updated":"2026-08-11 15:21:10.000000000","message":"The TestMergeNVMeBoardInfo test class has six separate methods that each contain a local \u0027import json\u0027 statement to parse assertion results, rather than importing json at the module level.\n\n**Severity**: SUGGESTION | **Confidence**: 0.8\n\n**Benefit**: This is a code quality issue that makes the tests harder to maintain. It also signals that the tests should use jsonutils from oslo_serialization for consistency with the code under test.\n\n**Recommendation**:\nAdd `import json` (or preferably use the already-available `from oslo_serialization import jsonutils`) at the module level and remove the six inline imports.","commit_id":"0ece3d90c95e271c9875fb6bb92b80e60d738c22"},{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"75490aa828304f0778f4426ab19da1bbe4cb5f6f","unresolved":false,"context_lines":[{"line_number":267,"context_line":"        old \u003d \u0027{\"cleanup_action\": \"sanitize_ces\", \"nvme_dev\": \"/dev/nvme0\"}\u0027"},{"line_number":268,"context_line":"        new \u003d \u0027{\"cleanup_action\": \"zero_wz\", \"nvme_dev\": \"/dev/nvme0\"}\u0027"},{"line_number":269,"context_line":"        result \u003d self._merge(old, new, \u0027allocated\u0027)"},{"line_number":270,"context_line":"        import json"},{"line_number":271,"context_line":""},{"line_number":272,"context_line":"        self.assertEqual(\u0027sanitize_ces\u0027, json.loads(result)[\u0027cleanup_action\u0027])"},{"line_number":273,"context_line":""}],"source_content_type":"text/x-python","patch_set":11,"id":"41babf3f_19da3ea5","line":270,"updated":"2026-08-13 04:59:07.000000000","message":"The TestMergeNVMeBoardInfo test class repeats `import json` inside each of its six test methods instead of importing json once at the module level. This is an anti-pattern that should use a module-level import or the already-available jsonutils module.\n\n**Severity**: SUGGESTION | **Confidence**: 0.9\n\n**Benefit**: Code smell that could trigger hacking checks and makes the test harder to read. Minor maintenance burden.\n\n**Recommendation**:\nAdd `import json` at the module level (or use jsonutils.loads for consistency with the production code being tested) and remove all six inline imports.","commit_id":"2fb1b5b4e81d79f57ff110dc1b4926ab784c1f40"}],"releasenotes/notes/add-nvme-generic-driver-a1b2c3d4e5f6.yaml":[{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"f26c2dd98eaebbeec53a85fff33719bae590e348","unresolved":false,"context_lines":[{"line_number":8,"context_line":"    configurable policy through ``[nvme] device_spec`` entries."},{"line_number":9,"context_line":"    See the `NVMe driver admin guide"},{"line_number":10,"context_line":"    \u003chttps://docs.openstack.org/cyborg/latest/admin/nvme_driver.html\u003e`_"},{"line_number":11,"context_line":"    for configuration details."},{"line_number":12,"context_line":"upgrade:"},{"line_number":13,"context_line":"  - |"},{"line_number":14,"context_line":"    The NVMe driver requires ``nvme-cli`` to be installed on compute"}],"source_content_type":"text/x-yaml","patch_set":9,"id":"85e5b0fa_60e5c668","line":11,"updated":"2026-08-11 15:21:10.000000000","message":"The release note links to https://docs.openstack.org/cyborg/latest/admin/nvme_driver.html for configuration details, but no such documentation page is created or referenced anywhere in the codebase.\n\n**Severity**: WARNING | **Confidence**: 0.8\n\n**Impact**: Users following the release note link will encounter a 404 error. Operators cannot find configuration guidance for the new [nvme] device_spec format.\n\n**Suggestion**:\nEither add the admin guide RST document in this change or remove the dead link from the release note and reference the configuration options help text instead.","commit_id":"0ece3d90c95e271c9875fb6bb92b80e60d738c22"},{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"f26c2dd98eaebbeec53a85fff33719bae590e348","unresolved":false,"context_lines":[{"line_number":15,"context_line":"    hosts.  The cyborg-agent will fail ``init_host()`` if nvme-cli is"},{"line_number":16,"context_line":"    not found and the NVMe driver is enabled in"},{"line_number":17,"context_line":"    ``[agent] enabled_drivers``."},{"line_number":18,"context_line":"deprecations:"},{"line_number":19,"context_line":"  - |"},{"line_number":20,"context_line":"    The vendor-specific SSD and Inspur NVMe drivers are deprecated in"},{"line_number":21,"context_line":"    favor of the new generic NVMe driver.  They will be removed in a"}],"source_content_type":"text/x-yaml","patch_set":9,"id":"4c7cc06f_404c6c4d","line":18,"updated":"2026-08-11 15:21:10.000000000","message":"The release note under \u0027deprecations\u0027 states that vendor-specific SSD and Inspur NVMe drivers are deprecated in favor of the new generic driver. However, no deprecation warning, LOG.warning, or deprecation marker is added to the InspurNVMeSSDDriver or SSDDriver code in this change.\n\n**Severity**: WARNING | **Confidence**: 0.9\n\n**Impact**: Operators who read the release note may be confused by the absence of runtime deprecation warnings. The deprecation is announced but not enforced or communicated through the usual OpenStack deprecation pattern (LOG.warning on import or first use).\n\n**Suggestion**:\nEither add a deprecation warning to the Inspur NVMe SSD driver (e.g. in __init__ or discover) using the standard oslo_log warning, or remove the deprecations section from the release note if the deprecation is not yet official.","commit_id":"0ece3d90c95e271c9875fb6bb92b80e60d738c22"},{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"a016e687c14f6fcd7f4553653bf46cf1135eab29","unresolved":false,"context_lines":[{"line_number":7,"context_line":"    NVMe sanitize (crypto-erase or block-erase) and write-zeroes, with"},{"line_number":8,"context_line":"    configurable policy through ``[nvme] device_spec`` entries."},{"line_number":9,"context_line":"    See the `NVMe driver admin guide"},{"line_number":10,"context_line":"    \u003chttps://docs.openstack.org/cyborg/latest/admin/nvme_driver.html\u003e`_"},{"line_number":11,"context_line":"    for configuration details."},{"line_number":12,"context_line":"upgrade:"},{"line_number":13,"context_line":"  - |"}],"source_content_type":"text/x-yaml","patch_set":12,"id":"c01e96c9_7f02f69a","line":10,"updated":"2026-08-14 15:33:02.000000000","message":"The release note references https://docs.openstack.org/cyborg/latest/admin/nvme_driver.html but no admin/nvme_driver.rst exists in the tree, and it deprecates the vendor-specific SSD and Inspur NVMe drivers without any deprecation logging or documentation in those drivers or their config help.\n\n**Severity**: WARNING | **Confidence**: 0.9\n\n**Impact**: Operators following the published release note hit a 404 doc link and see a deprecation commitment that no code or config warning reflects, eroding trust in upgrade guidance.\n\n**Suggestion**:\nAdd doc/source/admin/nvme_driver.rst (and register it in the admin toctree) or point at the existing contributor guide; add a deprecation LOG.warning in the inspur SSD/NVMe drivers\u0027 init_host and update the [agent] enabled_drivers help before announcing the deprecation in a release note.","commit_id":"d0ed397ba88c229ca4f0746f113bb90851a0fd88"}]}
