)]}'
{"cyborg/accelerator/drivers/mdev/devspec.py":[{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"8e0c49e1f5993a563404d09a8a82e1f2b9176b7e","unresolved":false,"context_lines":[{"line_number":47,"context_line":""},{"line_number":48,"context_line":"    def __init__(self, spec_dict):"},{"line_number":49,"context_line":"        if not isinstance(spec_dict, dict):"},{"line_number":50,"context_line":"            raise exception.PciConfigInvalidWhitelist("},{"line_number":51,"context_line":"                reason\u003df\u0027mdev device_spec entry is not a dict: {spec_dict}\u0027"},{"line_number":52,"context_line":"            )"},{"line_number":53,"context_line":"        self._validate_required_fields(spec_dict)"}],"source_content_type":"text/x-python","patch_set":13,"id":"c63d0213_4bbaa9b4","line":50,"range":{"start_line":50,"start_character":28,"end_line":50,"end_character":53},"updated":"2026-08-04 19:14:14.000000000","message":"hum ok, you have updated the reason so that ok but we may want to factor out a seperte shared invalidDevSpecConfig excption and have per driver version fo that at some point.\n\nthat also remins me we need to do the config option change next cycle to replace whitelist with devspec","commit_id":"1f7a750474ba150cf2c325b3623b89d53853fbdb"},{"author":{"_account_id":34452,"name":"Joan Gilabert","display_name":"jgilaber","email":"jgilaber@redhat.com","username":"jgilaber"},"change_message_id":"77d749f28b646667ebda9edf06351324026cc904","unresolved":false,"context_lines":[{"line_number":47,"context_line":""},{"line_number":48,"context_line":"    def __init__(self, spec_dict):"},{"line_number":49,"context_line":"        if not isinstance(spec_dict, dict):"},{"line_number":50,"context_line":"            raise exception.PciConfigInvalidWhitelist("},{"line_number":51,"context_line":"                reason\u003df\u0027mdev device_spec entry is not a dict: {spec_dict}\u0027"},{"line_number":52,"context_line":"            )"},{"line_number":53,"context_line":"        self._validate_required_fields(spec_dict)"}],"source_content_type":"text/x-python","patch_set":13,"id":"a3e6d30c_54e76c60","line":50,"range":{"start_line":50,"start_character":28,"end_line":50,"end_character":53},"in_reply_to":"c63d0213_4bbaa9b4","updated":"2026-08-31 12:33:24.000000000","message":"good point, I\u0027ve created a new exception for the driver and a generic devspec one","commit_id":"1f7a750474ba150cf2c325b3623b89d53853fbdb"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"8e0c49e1f5993a563404d09a8a82e1f2b9176b7e","unresolved":true,"context_lines":[{"line_number":57,"context_line":"            spec_dict.get(\u0027max_instances\u0027),"},{"line_number":58,"context_line":"        )"},{"line_number":59,"context_line":"        resource_class \u003d spec_dict.get(\u0027resource_class\u0027)"},{"line_number":60,"context_line":"        if resource_class and not isinstance(resource_class, str):"},{"line_number":61,"context_line":"            LOG.warning("},{"line_number":62,"context_line":"                \u0027resource class is not string, ignoring %s\u0027, resource_class"},{"line_number":63,"context_line":"            )"},{"line_number":64,"context_line":"            resource_class \u003d None"},{"line_number":65,"context_line":"        self.resource_class \u003d resource_class"},{"line_number":66,"context_line":"        self.traits \u003d self._parse_traits("},{"line_number":67,"context_line":"            spec_dict.get(\u0027traits\u0027, []),"}],"source_content_type":"text/x-python","patch_set":13,"id":"85a7ff6c_eb981c61","line":64,"range":{"start_line":60,"start_character":7,"end_line":64,"end_character":33},"updated":"2026-08-04 19:14:14.000000000","message":"if its defiend and its not valid im inclided to raise exception.PciConfigInvalidWhitelist here as well and treat it as a fatal start up error.\n\n\nits hard to make that change later but we can do that now in this new driver.\n\nif it unset we shoudl auto generate it later form the mdev_type but if its set to anythign that is not a valid resouce class when normalsied we shoudl error","commit_id":"1f7a750474ba150cf2c325b3623b89d53853fbdb"},{"author":{"_account_id":34452,"name":"Joan Gilabert","display_name":"jgilaber","email":"jgilaber@redhat.com","username":"jgilaber"},"change_message_id":"77d749f28b646667ebda9edf06351324026cc904","unresolved":true,"context_lines":[{"line_number":57,"context_line":"            spec_dict.get(\u0027max_instances\u0027),"},{"line_number":58,"context_line":"        )"},{"line_number":59,"context_line":"        resource_class \u003d spec_dict.get(\u0027resource_class\u0027)"},{"line_number":60,"context_line":"        if resource_class and not isinstance(resource_class, str):"},{"line_number":61,"context_line":"            LOG.warning("},{"line_number":62,"context_line":"                \u0027resource class is not string, ignoring %s\u0027, resource_class"},{"line_number":63,"context_line":"            )"},{"line_number":64,"context_line":"            resource_class \u003d None"},{"line_number":65,"context_line":"        self.resource_class \u003d resource_class"},{"line_number":66,"context_line":"        self.traits \u003d self._parse_traits("},{"line_number":67,"context_line":"            spec_dict.get(\u0027traits\u0027, []),"}],"source_content_type":"text/x-python","patch_set":13,"id":"b1a3a9c3_42b8e4c2","line":64,"range":{"start_line":60,"start_character":7,"end_line":64,"end_character":33},"in_reply_to":"85a7ff6c_eb981c61","updated":"2026-08-31 12:33:24.000000000","message":"fair, I\u0027ve changed it to raise","commit_id":"1f7a750474ba150cf2c325b3623b89d53853fbdb"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"8e0c49e1f5993a563404d09a8a82e1f2b9176b7e","unresolved":true,"context_lines":[{"line_number":83,"context_line":"                f\u0027or mdev_type: {spec_dict}\u0027"},{"line_number":84,"context_line":"            )"},{"line_number":85,"context_line":""},{"line_number":86,"context_line":"    @staticmethod"},{"line_number":87,"context_line":"    def _parse_max_instances(value):"},{"line_number":88,"context_line":"        \"\"\"Parse and validate max_instances."},{"line_number":89,"context_line":""},{"line_number":90,"context_line":"        :param value: Raw value from the spec dict, or None."},{"line_number":91,"context_line":"        :returns: A positive int, or None if absent or"},{"line_number":92,"context_line":"            invalid."},{"line_number":93,"context_line":"        \"\"\""},{"line_number":94,"context_line":"        if value is None:"},{"line_number":95,"context_line":"            return None"},{"line_number":96,"context_line":"        try:"},{"line_number":97,"context_line":"            max_inst \u003d int(value)"},{"line_number":98,"context_line":"        except (ValueError, TypeError):"},{"line_number":99,"context_line":"            LOG.warning("},{"line_number":100,"context_line":"                \u0027Invalid max_instances value %r in mdev \u0027"},{"line_number":101,"context_line":"                \u0027device_spec, ignoring cap\u0027,"},{"line_number":102,"context_line":"                value,"},{"line_number":103,"context_line":"            )"},{"line_number":104,"context_line":"            return None"},{"line_number":105,"context_line":"        if max_inst \u003c 0:"},{"line_number":106,"context_line":"            LOG.warning("},{"line_number":107,"context_line":"                \u0027Negative max_instances value %d in mdev \u0027"},{"line_number":108,"context_line":"                \u0027device_spec, ignoring cap\u0027,"},{"line_number":109,"context_line":"                max_inst,"},{"line_number":110,"context_line":"            )"},{"line_number":111,"context_line":"            return None"},{"line_number":112,"context_line":"        return max_inst"},{"line_number":113,"context_line":""},{"line_number":114,"context_line":"    @staticmethod"},{"line_number":115,"context_line":"    def _parse_traits(raw_traits):"},{"line_number":116,"context_line":"        \"\"\"Parse and validate traits list."}],"source_content_type":"text/x-python","patch_set":13,"id":"3e11d36e_a2221f3a","line":113,"range":{"start_line":86,"start_character":0,"end_line":113,"end_character":1},"updated":"2026-08-04 19:14:14.000000000","message":"same here if you spcify an invlaid max_instnaces it shoudl prevent the agent form starting","commit_id":"1f7a750474ba150cf2c325b3623b89d53853fbdb"},{"author":{"_account_id":34452,"name":"Joan Gilabert","display_name":"jgilaber","email":"jgilaber@redhat.com","username":"jgilaber"},"change_message_id":"77d749f28b646667ebda9edf06351324026cc904","unresolved":false,"context_lines":[{"line_number":83,"context_line":"                f\u0027or mdev_type: {spec_dict}\u0027"},{"line_number":84,"context_line":"            )"},{"line_number":85,"context_line":""},{"line_number":86,"context_line":"    @staticmethod"},{"line_number":87,"context_line":"    def _parse_max_instances(value):"},{"line_number":88,"context_line":"        \"\"\"Parse and validate max_instances."},{"line_number":89,"context_line":""},{"line_number":90,"context_line":"        :param value: Raw value from the spec dict, or None."},{"line_number":91,"context_line":"        :returns: A positive int, or None if absent or"},{"line_number":92,"context_line":"            invalid."},{"line_number":93,"context_line":"        \"\"\""},{"line_number":94,"context_line":"        if value is None:"},{"line_number":95,"context_line":"            return None"},{"line_number":96,"context_line":"        try:"},{"line_number":97,"context_line":"            max_inst \u003d int(value)"},{"line_number":98,"context_line":"        except (ValueError, TypeError):"},{"line_number":99,"context_line":"            LOG.warning("},{"line_number":100,"context_line":"                \u0027Invalid max_instances value %r in mdev \u0027"},{"line_number":101,"context_line":"                \u0027device_spec, ignoring cap\u0027,"},{"line_number":102,"context_line":"                value,"},{"line_number":103,"context_line":"            )"},{"line_number":104,"context_line":"            return None"},{"line_number":105,"context_line":"        if max_inst \u003c 0:"},{"line_number":106,"context_line":"            LOG.warning("},{"line_number":107,"context_line":"                \u0027Negative max_instances value %d in mdev \u0027"},{"line_number":108,"context_line":"                \u0027device_spec, ignoring cap\u0027,"},{"line_number":109,"context_line":"                max_inst,"},{"line_number":110,"context_line":"            )"},{"line_number":111,"context_line":"            return None"},{"line_number":112,"context_line":"        return max_inst"},{"line_number":113,"context_line":""},{"line_number":114,"context_line":"    @staticmethod"},{"line_number":115,"context_line":"    def _parse_traits(raw_traits):"},{"line_number":116,"context_line":"        \"\"\"Parse and validate traits list."}],"source_content_type":"text/x-python","patch_set":13,"id":"713d9dad_74167758","line":113,"range":{"start_line":86,"start_character":0,"end_line":113,"end_character":1},"in_reply_to":"3e11d36e_a2221f3a","updated":"2026-08-31 12:33:24.000000000","message":"Done","commit_id":"1f7a750474ba150cf2c325b3623b89d53853fbdb"},{"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":"55a786a72551fb6e35ebbc5de5fc5b81b055290c","unresolved":false,"context_lines":[{"line_number":126,"context_line":"            )"},{"line_number":127,"context_line":"            return []"},{"line_number":128,"context_line":"        traits \u003d []"},{"line_number":129,"context_line":"        for trait in raw_traits:"},{"line_number":130,"context_line":"            if not isinstance(trait, str):"},{"line_number":131,"context_line":"                LOG.warning(\u0027trait is not a string, ignoring: %s \u0027, trait)"},{"line_number":132,"context_line":"                continue"}],"source_content_type":"text/x-python","patch_set":13,"id":"58af3fd6_6dd14a9a","line":129,"updated":"2026-08-04 17:07:14.000000000","message":"The _parse_traits method validates that each trait is a string via isinstance(trait, str) but does not check for empty strings. An empty string passes validation and is stored. Later, _get_traits calls os_traits.normalize_name on it, which produces \u0027CUSTOM_\u0027 — an invalid Placement trait name that...\n\n**Severity**: SUGGESTION | **Confidence**: 0.8\n\n**Benefit**: An operator who accidentally includes an empty string in the traits list (e.g., {\"traits\": [\"CUSTOM_FAST\", \"\"]}) would get an invalid CUSTOM_ trait sent to Placement during resource reporting, causing a Placement API error. The error would surface during agent discovery/reporting, potentially blo...\n\n**Recommendation**:\nAdd an emptiness check alongside the isinstance check in _parse_traits. For example: \u0027if not isinstance(trait, str) or not trait: LOG.warning(...); continue\u0027. This is consistent with the validation already applied to address/mdev_type (checked for falsiness in _validate_required_fields) and max_instances (checked for negativity).","commit_id":"1f7a750474ba150cf2c325b3623b89d53853fbdb"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"8e0c49e1f5993a563404d09a8a82e1f2b9176b7e","unresolved":true,"context_lines":[{"line_number":130,"context_line":"            if not isinstance(trait, str):"},{"line_number":131,"context_line":"                LOG.warning(\u0027trait is not a string, ignoring: %s \u0027, trait)"},{"line_number":132,"context_line":"                continue"},{"line_number":133,"context_line":"            traits.append(trait)"},{"line_number":134,"context_line":"        return traits"},{"line_number":135,"context_line":""},{"line_number":136,"context_line":"    @property"}],"source_content_type":"text/x-python","patch_set":13,"id":"ed4c5799_c7bc539b","line":133,"range":{"start_line":133,"start_character":10,"end_line":133,"end_character":32},"updated":"2026-08-04 19:14:14.000000000","message":"so we proably shoudl to the os traits normalsistion here.","commit_id":"1f7a750474ba150cf2c325b3623b89d53853fbdb"},{"author":{"_account_id":34452,"name":"Joan Gilabert","display_name":"jgilaber","email":"jgilaber@redhat.com","username":"jgilaber"},"change_message_id":"77d749f28b646667ebda9edf06351324026cc904","unresolved":false,"context_lines":[{"line_number":130,"context_line":"            if not isinstance(trait, str):"},{"line_number":131,"context_line":"                LOG.warning(\u0027trait is not a string, ignoring: %s \u0027, trait)"},{"line_number":132,"context_line":"                continue"},{"line_number":133,"context_line":"            traits.append(trait)"},{"line_number":134,"context_line":"        return traits"},{"line_number":135,"context_line":""},{"line_number":136,"context_line":"    @property"}],"source_content_type":"text/x-python","patch_set":13,"id":"9cfe4cf6_23a2483b","line":133,"range":{"start_line":133,"start_character":10,"end_line":133,"end_character":32},"in_reply_to":"ed4c5799_c7bc539b","updated":"2026-08-31 12:33:24.000000000","message":"Done","commit_id":"1f7a750474ba150cf2c325b3623b89d53853fbdb"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"8e0c49e1f5993a563404d09a8a82e1f2b9176b7e","unresolved":true,"context_lines":[{"line_number":133,"context_line":"            traits.append(trait)"},{"line_number":134,"context_line":"        return traits"},{"line_number":135,"context_line":""},{"line_number":136,"context_line":"    @property"},{"line_number":137,"context_line":"    def specificity(self):"},{"line_number":138,"context_line":"        \"\"\"Return specificity score (lower is more specific)."},{"line_number":139,"context_line":""},{"line_number":140,"context_line":"        Used for ordering specs so that more specific matches"},{"line_number":141,"context_line":"        take priority."},{"line_number":142,"context_line":""},{"line_number":143,"context_line":"        :returns: Integer specificity score."},{"line_number":144,"context_line":"        \"\"\""},{"line_number":145,"context_line":"        score \u003d 0"},{"line_number":146,"context_line":"        if self.address \u003d\u003d WILDCARD:"},{"line_number":147,"context_line":"            score +\u003d 2"},{"line_number":148,"context_line":"        if self.mdev_type \u003d\u003d WILDCARD:"},{"line_number":149,"context_line":"            score +\u003d 1"},{"line_number":150,"context_line":"        return score"},{"line_number":151,"context_line":""},{"line_number":152,"context_line":"    def match(self, pci_address, type_name):"},{"line_number":153,"context_line":"        \"\"\"Check if this spec matches a device/type pair."}],"source_content_type":"text/x-python","patch_set":13,"id":"f560ef4f_77befeea","line":150,"range":{"start_line":136,"start_character":1,"end_line":150,"end_character":20},"updated":"2026-08-04 19:14:14.000000000","message":"intersting choice\n\nin nova we consider it operaotr error to have overlaping device specs\n\ni belive we take the first of you do it but it not something we really wanted to supprot\n\nhaving precendce based on teh number of wild card can work wiht a bias but its alos complex to reason about.\n\nwhy not just use the order in the config and have first match win.\n\n\nnote that wildcarding the mdev_type is not part of the appoved spec\n\nhttps://specs.openstack.org/openstack/cyborg-specs/specs/2026.2/approved/generic-mdev-driver.html#mdevbusmanager-class-design\nit was intened to be a fixed value.\n\n\nwe didnt dicuss overlaping mapping and precedence either so im inclidne to say this is overly complx and we shoudl either error if a device matches mutlipel or keep it simple for now and take the first match in config order","commit_id":"1f7a750474ba150cf2c325b3623b89d53853fbdb"},{"author":{"_account_id":34452,"name":"Joan Gilabert","display_name":"jgilaber","email":"jgilaber@redhat.com","username":"jgilaber"},"change_message_id":"77d749f28b646667ebda9edf06351324026cc904","unresolved":true,"context_lines":[{"line_number":133,"context_line":"            traits.append(trait)"},{"line_number":134,"context_line":"        return traits"},{"line_number":135,"context_line":""},{"line_number":136,"context_line":"    @property"},{"line_number":137,"context_line":"    def specificity(self):"},{"line_number":138,"context_line":"        \"\"\"Return specificity score (lower is more specific)."},{"line_number":139,"context_line":""},{"line_number":140,"context_line":"        Used for ordering specs so that more specific matches"},{"line_number":141,"context_line":"        take priority."},{"line_number":142,"context_line":""},{"line_number":143,"context_line":"        :returns: Integer specificity score."},{"line_number":144,"context_line":"        \"\"\""},{"line_number":145,"context_line":"        score \u003d 0"},{"line_number":146,"context_line":"        if self.address \u003d\u003d WILDCARD:"},{"line_number":147,"context_line":"            score +\u003d 2"},{"line_number":148,"context_line":"        if self.mdev_type \u003d\u003d WILDCARD:"},{"line_number":149,"context_line":"            score +\u003d 1"},{"line_number":150,"context_line":"        return score"},{"line_number":151,"context_line":""},{"line_number":152,"context_line":"    def match(self, pci_address, type_name):"},{"line_number":153,"context_line":"        \"\"\"Check if this spec matches a device/type pair."}],"source_content_type":"text/x-python","patch_set":13,"id":"126853ab_c6ecad2f","line":150,"range":{"start_line":136,"start_character":1,"end_line":150,"end_character":20},"in_reply_to":"f560ef4f_77befeea","updated":"2026-08-31 12:33:24.000000000","message":"agreed, this was added because of the possibility of type wildcards, once that is removed we can remove this as well and simplify the logic","commit_id":"1f7a750474ba150cf2c325b3623b89d53853fbdb"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"8e0c49e1f5993a563404d09a8a82e1f2b9176b7e","unresolved":true,"context_lines":[{"line_number":166,"context_line":"            f\u0027mdev_type\u003d{self.mdev_type})\u0027"},{"line_number":167,"context_line":"        )"},{"line_number":168,"context_line":""},{"line_number":169,"context_line":"    @staticmethod"},{"line_number":170,"context_line":"    def from_config(spec_str):"},{"line_number":171,"context_line":"        \"\"\"Parse a single JSON config string into a spec."},{"line_number":172,"context_line":""}],"source_content_type":"text/x-python","patch_set":13,"id":"5c5ade30_ac5cd4b6","line":169,"range":{"start_line":169,"start_character":5,"end_line":169,"end_character":17},"updated":"2026-08-04 19:14:14.000000000","message":"this shoudl be a class method\n\nits a constructor function","commit_id":"1f7a750474ba150cf2c325b3623b89d53853fbdb"},{"author":{"_account_id":34452,"name":"Joan Gilabert","display_name":"jgilaber","email":"jgilaber@redhat.com","username":"jgilaber"},"change_message_id":"77d749f28b646667ebda9edf06351324026cc904","unresolved":false,"context_lines":[{"line_number":166,"context_line":"            f\u0027mdev_type\u003d{self.mdev_type})\u0027"},{"line_number":167,"context_line":"        )"},{"line_number":168,"context_line":""},{"line_number":169,"context_line":"    @staticmethod"},{"line_number":170,"context_line":"    def from_config(spec_str):"},{"line_number":171,"context_line":"        \"\"\"Parse a single JSON config string into a spec."},{"line_number":172,"context_line":""}],"source_content_type":"text/x-python","patch_set":13,"id":"1580edbf_77590e14","line":169,"range":{"start_line":169,"start_character":5,"end_line":169,"end_character":17},"in_reply_to":"5c5ade30_ac5cd4b6","updated":"2026-08-31 12:33:24.000000000","message":"Done","commit_id":"1f7a750474ba150cf2c325b3623b89d53853fbdb"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"8e0c49e1f5993a563404d09a8a82e1f2b9176b7e","unresolved":true,"context_lines":[{"line_number":182,"context_line":"                reason\u003d\u0027Invalid mdev device_spec entry: %s\u0027 % spec_str"},{"line_number":183,"context_line":"            )"},{"line_number":184,"context_line":"        return MdevDeviceSpec(spec_dict)"},{"line_number":185,"context_line":""},{"line_number":186,"context_line":"    @staticmethod"},{"line_number":187,"context_line":"    def from_config_list(spec_strings):"},{"line_number":188,"context_line":"        \"\"\"Parse a list of JSON config strings into specs."},{"line_number":189,"context_line":""},{"line_number":190,"context_line":"        Parses all ``[mdev] device_spec`` entries, deduplicates"},{"line_number":191,"context_line":"        by ``(address, mdev_type)`` (last entry wins), and"},{"line_number":192,"context_line":"        returns specs sorted by specificity (most specific"},{"line_number":193,"context_line":"        first)."},{"line_number":194,"context_line":""},{"line_number":195,"context_line":"        :param spec_strings: List of JSON-encoded strings."},{"line_number":196,"context_line":"        :returns: A list of :class:`MdevDeviceSpec` objects"},{"line_number":197,"context_line":"            sorted by specificity."},{"line_number":198,"context_line":"        \"\"\""},{"line_number":199,"context_line":"        seen \u003d {}"},{"line_number":200,"context_line":"        for spec_str in spec_strings:"},{"line_number":201,"context_line":"            spec \u003d MdevDeviceSpec.from_config(spec_str)"},{"line_number":202,"context_line":"            key \u003d (spec.address, spec.mdev_type)"},{"line_number":203,"context_line":"            if key in seen:"},{"line_number":204,"context_line":"                LOG.warning("},{"line_number":205,"context_line":"                    \u0027Duplicate mdev device_spec for \u0027"},{"line_number":206,"context_line":"                    \u0027(address\u003d%s, mdev_type\u003d%s), \u0027"},{"line_number":207,"context_line":"                    \u0027overwriting previous entry\u0027,"},{"line_number":208,"context_line":"                    spec.address,"},{"line_number":209,"context_line":"                    spec.mdev_type,"},{"line_number":210,"context_line":"                )"},{"line_number":211,"context_line":"            seen[key] \u003d spec"},{"line_number":212,"context_line":"        specs \u003d list(seen.values())"},{"line_number":213,"context_line":"        specs.sort(key\u003dlambda s: s.specificity)"},{"line_number":214,"context_line":"        return specs"},{"line_number":215,"context_line":""},{"line_number":216,"context_line":"    @staticmethod"},{"line_number":217,"context_line":"    def build_filters(specs):"},{"line_number":218,"context_line":"        \"\"\"Build PCI address and mdev type filters from specs."}],"source_content_type":"text/x-python","patch_set":13,"id":"4bed6d58_72b84f32","line":215,"range":{"start_line":185,"start_character":1,"end_line":215,"end_character":1},"updated":"2026-08-04 19:14:14.000000000","message":"i dont think this is correct\n\nosloconfg will returhn the list of string and we can just parse that into a list of objects","commit_id":"1f7a750474ba150cf2c325b3623b89d53853fbdb"},{"author":{"_account_id":34452,"name":"Joan Gilabert","display_name":"jgilaber","email":"jgilaber@redhat.com","username":"jgilaber"},"change_message_id":"77d749f28b646667ebda9edf06351324026cc904","unresolved":true,"context_lines":[{"line_number":182,"context_line":"                reason\u003d\u0027Invalid mdev device_spec entry: %s\u0027 % spec_str"},{"line_number":183,"context_line":"            )"},{"line_number":184,"context_line":"        return MdevDeviceSpec(spec_dict)"},{"line_number":185,"context_line":""},{"line_number":186,"context_line":"    @staticmethod"},{"line_number":187,"context_line":"    def from_config_list(spec_strings):"},{"line_number":188,"context_line":"        \"\"\"Parse a list of JSON config strings into specs."},{"line_number":189,"context_line":""},{"line_number":190,"context_line":"        Parses all ``[mdev] device_spec`` entries, deduplicates"},{"line_number":191,"context_line":"        by ``(address, mdev_type)`` (last entry wins), and"},{"line_number":192,"context_line":"        returns specs sorted by specificity (most specific"},{"line_number":193,"context_line":"        first)."},{"line_number":194,"context_line":""},{"line_number":195,"context_line":"        :param spec_strings: List of JSON-encoded strings."},{"line_number":196,"context_line":"        :returns: A list of :class:`MdevDeviceSpec` objects"},{"line_number":197,"context_line":"            sorted by specificity."},{"line_number":198,"context_line":"        \"\"\""},{"line_number":199,"context_line":"        seen \u003d {}"},{"line_number":200,"context_line":"        for spec_str in spec_strings:"},{"line_number":201,"context_line":"            spec \u003d MdevDeviceSpec.from_config(spec_str)"},{"line_number":202,"context_line":"            key \u003d (spec.address, spec.mdev_type)"},{"line_number":203,"context_line":"            if key in seen:"},{"line_number":204,"context_line":"                LOG.warning("},{"line_number":205,"context_line":"                    \u0027Duplicate mdev device_spec for \u0027"},{"line_number":206,"context_line":"                    \u0027(address\u003d%s, mdev_type\u003d%s), \u0027"},{"line_number":207,"context_line":"                    \u0027overwriting previous entry\u0027,"},{"line_number":208,"context_line":"                    spec.address,"},{"line_number":209,"context_line":"                    spec.mdev_type,"},{"line_number":210,"context_line":"                )"},{"line_number":211,"context_line":"            seen[key] \u003d spec"},{"line_number":212,"context_line":"        specs \u003d list(seen.values())"},{"line_number":213,"context_line":"        specs.sort(key\u003dlambda s: s.specificity)"},{"line_number":214,"context_line":"        return specs"},{"line_number":215,"context_line":""},{"line_number":216,"context_line":"    @staticmethod"},{"line_number":217,"context_line":"    def build_filters(specs):"},{"line_number":218,"context_line":"        \"\"\"Build PCI address and mdev type filters from specs."}],"source_content_type":"text/x-python","patch_set":13,"id":"5cdd853d_68632aec","line":215,"range":{"start_line":185,"start_character":1,"end_line":215,"end_character":1},"in_reply_to":"4bed6d58_72b84f32","updated":"2026-08-31 12:33:24.000000000","message":"I simplified the method slightly by removing the specificity, but other than that, what is incorrect? The method does what you described in the second sentence","commit_id":"1f7a750474ba150cf2c325b3623b89d53853fbdb"},{"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":"7c96ba83670a64b45538690f46ab456dec824219","unresolved":false,"context_lines":[{"line_number":145,"context_line":"        :returns: True if this spec matches the given pair."},{"line_number":146,"context_line":"        \"\"\""},{"line_number":147,"context_line":"        addr_match \u003d self.address \u003d\u003d WILDCARD or self.address \u003d\u003d pci_address"},{"line_number":148,"context_line":"        return addr_match and self.mdev_type \u003d\u003d type_name"},{"line_number":149,"context_line":""},{"line_number":150,"context_line":"    def __repr__(self):"},{"line_number":151,"context_line":"        return ("}],"source_content_type":"text/x-python","patch_set":14,"id":"21074ff2_045a8593","line":148,"updated":"2026-08-31 12:57:50.000000000","message":"MdevDeviceSpec.match() applies the wildcard only to the address and compares the mdev type with strict equality (self.mdev_type \u003d\u003d type_name). The [mdev] device_spec help in cyborg/conf/mdev.py explicitly documents mdev_type \u0027Use \"*\" to match all supported types\u0027, and the help example uses a wildcard entry. A spec with mdev_type \u0027*\u0027 can never match a real type name, so discover() skips every type (driver.py:334 \u0027if not spec: continue\u0027) and returns an empty device list with only an INFO log. The wildcard is also leaked into build_filters: with a mix of \u0027*\u0027 and concrete types, type_filter becomes e.g. [\u0027*\u0027, \u0027nvidia-319\u0027], which MdevBusManager.get_mdev_types does not treat as wildcard, so wildcard-spec types are dropped even at the sysfs enumeration stage.\n\n**Severity**: HIGH | **Confidence**: 0.92\n\n**Impact**: An operator following the documented configuration gets zero reported resources in Placement without any error or warning, making the driver appear functional but completely non-operational for wildcard-type deployments.\n\n**Priority**: Before merge\n**Recommendation**:\nIn match(), treat mdev_type \u003d\u003d WILDCARD as matching any type (e.g. type_match \u003d self.mdev_type \u003d\u003d WILDCARD or self.mdev_type \u003d\u003d type_name). Ensure build_filters collapses to [\u0027*\u0027] when any spec uses a wildcard type, mirroring the pci_filter logic. Add a discover() unit test with a wildcard mdev_type asserting devices and deployables are returned.","commit_id":"606e150380a27c914e54712bf539398105d2b5bb"},{"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":"7c96ba83670a64b45538690f46ab456dec824219","unresolved":false,"context_lines":[{"line_number":196,"context_line":"                )"},{"line_number":197,"context_line":"                continue"},{"line_number":198,"context_line":"            seen[key] \u003d spec"},{"line_number":199,"context_line":"        specs \u003d list(seen.values())"},{"line_number":200,"context_line":"        return specs"},{"line_number":201,"context_line":""},{"line_number":202,"context_line":"    @staticmethod"}],"source_content_type":"text/x-python","patch_set":14,"id":"9404187b_c80d8673","line":199,"updated":"2026-08-31 12:57:50.000000000","message":"from_config_list()\u0027s docstring promises specs are \u0027sorted by specificity\u0027, but the code returns them in insertion order (specs \u003d list(seen.values())), and find_spec() returns the first matching spec. With a wildcard-address spec listed before a spec for a concrete address (a pattern the config help encourages by mixing \u0027address\u0027: \u0027*\u0027 entries with specific ones), the wildcard spec wins and the specific spec\u0027s max_instances, resource_class, and traits overrides are silently ignored for that device. The unit test test_exact_match_preferred currently passes only vacuously: its first spec uses mdev_type \u0027*\u0027, which never matches because of CF-001, so ordering is never actually exercised; once CF-001 is fixed that test will fail, proving the ordering contract is not implemented.\n\n**Severity**: WARNING | **Confidence**: 0.88\n\n**Impact**: Specific overrides (instance caps, custom resource classes, traits) are silently dropped when a wildcard spec precedes a specific one, causing incorrect inventory and trait reporting to Placement; the existing test gives false confidence that the behavior is covered.\n\n**Suggestion**:\nImplement the documented ordering: sort specs so exact-address specs precede wildcard-address specs (and exact types precede wildcard types once CF-001 is fixed), e.g. key\u003d(spec.address \u003d\u003d WILDCARD, spec.mdev_type \u003d\u003d WILDCARD), before returning them in from_config_list(). After fixing CF-001, test_exact_match_preferred will then genuinely validate the preference.","commit_id":"606e150380a27c914e54712bf539398105d2b5bb"},{"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":"bad24d3d09e864fd6c63a128662b65e28d36aa41","unresolved":false,"context_lines":[{"line_number":97,"context_line":"        try:"},{"line_number":98,"context_line":"            max_inst \u003d int(value)"},{"line_number":99,"context_line":"        except (ValueError, TypeError):"},{"line_number":100,"context_line":"            raise exception.InvalidMdevDevSpecConfig("},{"line_number":101,"context_line":"                reason\u003d("},{"line_number":102,"context_line":"                    f\u0027Invalid max_instances value {value} in mdev device_spec\u0027"},{"line_number":103,"context_line":"                ),"}],"source_content_type":"text/x-python","patch_set":15,"id":"74201c3f_6870c6cd","line":100,"updated":"2026-08-31 15:24:13.000000000","message":"_parse_max_instances contains `return None` statements immediately after both `raise exception.InvalidMdevDevSpecConfig` blocks, so they can never execute, and the docstring states \":returns: A positive int, or None if absent or invalid\" even though invalid values raise rather than return None.\n\n**Severity**: SUGGESTION | **Confidence**: 0.85\n\n**Impact**: A maintainer reading the function or its docstring can conclude invalid max_instances yields None (uncapped reporting) instead of an exception, inviting edits on an unreachable path or incorrect caller assumptions about the contract.\n\n**Recommendation**:\nDelete the unreachable `return None` statements at devspec.py:105 and devspec.py:112 and correct the docstring to \":returns: A non-negative int, or None if absent\" with the raise behavior documented.","commit_id":"f33ad997ed7dfccdf0d0a8c8a036bdf5a2e2a48c"},{"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":"62014530dcfc7a62a4050dc1f4e2f21b73908f40","unresolved":false,"context_lines":[{"line_number":143,"context_line":"        :returns: True if this spec matches the given pair."},{"line_number":144,"context_line":"        \"\"\""},{"line_number":145,"context_line":"        addr_match \u003d self.address \u003d\u003d WILDCARD or self.address \u003d\u003d pci_address"},{"line_number":146,"context_line":"        return addr_match and self.mdev_type \u003d\u003d type_name"},{"line_number":147,"context_line":""},{"line_number":148,"context_line":"    def __repr__(self):"},{"line_number":149,"context_line":"        return ("}],"source_content_type":"text/x-python","patch_set":16,"id":"8be77dd0_4d7688f7","line":146,"updated":"2026-09-01 10:04:27.000000000","message":"MdevDeviceSpec.match() honours the \u0027*\u0027 wildcard only for address; mdev_type is compared for exact equality, so a spec with mdev_type\u003d\u0027*\u0027 can never match a real sysfs type name. Meanwhile build_filters() still emits a [\u0027*\u0027] type filter that MdevBusManager.get_mdev_types() interprets as \u0027return all types\u0027, the [mdev] device_spec help example still shows device_spec \u003d {\"address\": \"*\", \"mdev_type\": \"*\", \"max_instances\": 8}, and test_wildcard_type asserts the [\u0027*\u0027] filter is produced. discover() then discards every discovered type via find_spec(), so an operator copying the documented example gets zero reported resources with no warning or error.\n\n**Severity**: HIGH | **Confidence**: 0.85\n\n**Impact**: A configuration shown in the shipped option help produces no accelerator inventory in Placement and no log output indicating that no spec matched; operators get silent no-op reporting and must debug from scratch.\n\n**Priority**: Before merge\n**Recommendation**:\nPick one semantics and make code, help, and tests agree: either implement wildcard mdev_type in match() (self.mdev_type \u003d\u003d WILDCARD or self.mdev_type \u003d\u003d type_name) and restore the help line, or remove wildcard-type support by dropping the \u0027*\u0027 example from the [mdev] device_spec help and collapsing \u0027*\u0027 out of the type filter in build_filters(). Add an end-to-end discover() test using mdev_type\u003d\u0027*\u0027 asserting the chosen outcome.","commit_id":"70c2e9c96e80acdaa11c2c09f1ca7226be089e55"},{"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":"09162a35d8e56dc27dcb763bd9d6f2276da69e33","unresolved":false,"context_lines":[{"line_number":142,"context_line":"        :param type_name: mdev type name."},{"line_number":143,"context_line":"        :returns: True if this spec matches the given pair."},{"line_number":144,"context_line":"        \"\"\""},{"line_number":145,"context_line":"        addr_match \u003d self.address \u003d\u003d WILDCARD or self.address \u003d\u003d pci_address"},{"line_number":146,"context_line":"        return addr_match and self.mdev_type \u003d\u003d type_name"},{"line_number":147,"context_line":""},{"line_number":148,"context_line":"    def __repr__(self):"}],"source_content_type":"text/x-python","patch_set":17,"id":"b1f93ce1_403ae783","line":145,"updated":"2026-09-18 14:11:36.000000000","message":"MdevDeviceSpec.match() honors the \u0027*\u0027 wildcard only for address, not for mdev_type: it returns \u0027addr_match and self.mdev_type \u003d\u003d type_name\u0027, so a spec with mdev_type \u0027*\u0027 never matches any real sysfs type name. However the rest of the pipeline explicitly supports wildcard types: build_filters() converts a wildcard type into type_filter [\u0027*\u0027], and MdevBusManager.get_mdev_types documents [\u0027*\u0027] as \u0027return all supported types\u0027. Discovery therefore enumerates every supported type on the parent, find_spec() then fails to match each one, and the driver skips it (driver.py \u0027if not spec: continue\u0027), yielding an empty dep_list and no DriverDevice. The operator-facing example shipped in the [mdev] device_spec help text (cyborg/conf/mdev.py:54), \u0027device_spec \u003d {\"address\": \"*\", \"mdev_type\": \"*\", \"max_instances\": 8}\u0027, thus silently reports nothing to Placement. This commit also removed the \u0027Use * to match all supported types\u0027 sentence from the mdev_type bullet while leaving that example, making the help text self-contradictory.\n\n**Severity**: HIGH | **Confidence**: 0.85\n\n**Impact**: An operator who configures the shipped wildcard example (the natural choice for hosts with a homogeneous GPU fleet) gets a driver that logs \u0027Discovered N mdev parent device(s)\u0027 and then silently reports zero resources to Placement, with no error or warning pointing at the config. Mixed configs (e.g. one exact-type spec plus one wildcard-type spec) silently drop every non-exactly-listed type. Debugging requires reading driver source; the wildcard address path works, so the asymmetry is hard to anticipate.\n\n**Priority**: Before merge\n**Recommendation**:\nHonor the wildcard for mdev_type in MdevDeviceSpec.match, e.g. \u0027type_match \u003d self.mdev_type \u003d\u003d WILDCARD or self.mdev_type \u003d\u003d type_name; return addr_match and type_match\u0027, matching the documented [\u0027*\u0027] semantics of get_mdev_types and the address handling. Add an end-to-end GenericMdevDriver.discover test with a wildcard mdev_type spec asserting deployables are produced. If wildcard types are intentionally unsupported instead, remove the wildcard branch from build_filters and replace the example in the [mdev] device_spec help with an exact-type entry so config and behavior agree.","commit_id":"cfe1a07869dcf97e35c0ceffa49d6922086bfe3f"}],"cyborg/accelerator/drivers/mdev/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":"cf81eef0398f3df841744549e79f74b33c9f26af","unresolved":false,"context_lines":[{"line_number":232,"context_line":"        :returns: A list of trait strings."},{"line_number":233,"context_line":"        \"\"\""},{"line_number":234,"context_line":"        traits \u003d [constants.OWNER_CYBORG]"},{"line_number":235,"context_line":"        extra \u003d spec.get(\u0027traits\u0027, [])"},{"line_number":236,"context_line":"        extra_traits \u003d ["},{"line_number":237,"context_line":"            os_traits.normalize_name(trait.replace(\u0027CUSTOM_\u0027, \u0027\u0027))"},{"line_number":238,"context_line":"            for trait in extra"}],"source_content_type":"text/x-python","patch_set":1,"id":"9e526c96_c17fb15f","line":235,"updated":"2026-07-13 14:12:32.000000000","message":"The _get_traits method retrieves the \u0027traits\u0027 key from the config spec via spec.get(\u0027traits\u0027, []) and immediately iterates over it in a list comprehension. If an operator provides traits as a string (e.g. \"traits\": \"CUSTOM_FAST\" instead of [\"CUSTOM_FAST\"]), the comprehension iterates over individ...\n\n**Severity**: WARNING | **Confidence**: 0.8\n\n**Impact**: Operator misconfiguration of traits as a string silently produces wrong Placement traits, affecting scheduling. If traits is null or non-iterable, the entire mdev discovery crashes with an unhandled TypeError, preventing all mdev devices from being reported.\n\n**Suggestion**:\nAdd a type check before the list comprehension, e.g.: extra \u003d spec.get(\u0027traits\u0027, []) if not isinstance(extra, list): LOG.warning(\u0027traits in mdev device_spec is not a list, ignoring: %r\u0027, extra) extra \u003d [] Then proceed with the comprehension. This prevents both the silent wrong-results case and the crash.","commit_id":"5795bcd108c61d36a8b8dcf3983dec96194d26d4"},{"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":"cf81eef0398f3df841744549e79f74b33c9f26af","unresolved":false,"context_lines":[{"line_number":316,"context_line":"        created \u003d mdev_type_info[\u0027created_instances\u0027]"},{"line_number":317,"context_line":"        num_accelerators \u003d available + created"},{"line_number":318,"context_line":""},{"line_number":319,"context_line":"        max_inst \u003d spec.get(\u0027max_instances\u0027)"},{"line_number":320,"context_line":"        if max_inst is not None:"},{"line_number":321,"context_line":"            try:"},{"line_number":322,"context_line":"                max_inst \u003d int(max_inst)"}],"source_content_type":"text/x-python","patch_set":1,"id":"bd264fa1_5b90a65d","line":319,"updated":"2026-07-13 14:12:32.000000000","message":"In _generate_deployable, max_instances from the config spec is cast to int but not validated as non-negative. A negative value (e.g. -1) causes num_accelerators \u003d min(num_accelerators, -1) to become negative. This results in a DriverDeployable with a negative num_accelerators value and zero attac...\n\n**Severity**: WARNING | **Confidence**: 0.9\n\n**Impact**: A negative max_instances config value would cause the driver to report a deployable with a negative num_accelerators to Placement, which is semantically invalid and could cause downstream issues in resource tracking and scheduling.\n\n**Suggestion**:\nAfter the int conversion, validate that max_inst is non-negative: max_inst \u003d int(max_inst) if max_inst \u003c 0: LOG.warning(\u0027Invalid negative max_instances value %d for mdev type %s, ignoring cap\u0027, max_inst, type_name) else: num_accelerators \u003d min(num_accelerators, max_inst)","commit_id":"5795bcd108c61d36a8b8dcf3983dec96194d26d4"},{"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":"efd54905d1cfa4156d191edf3697c53c0e51d12c","unresolved":false,"context_lines":[{"line_number":487,"context_line":"                    ),"},{"line_number":488,"context_line":"                )"},{"line_number":489,"context_line":""},{"line_number":490,"context_line":"        LOG.info(\u0027mdev device_list: %s\u0027, device_list)"},{"line_number":491,"context_line":"        return device_list"}],"source_content_type":"text/x-python","patch_set":4,"id":"84066b4f_0a008e3c","line":490,"updated":"2026-07-20 11:04:08.000000000","message":"The discover() method logs the entire device_list (a list of DriverDevice objects, each containing nested deployables with multiple attach handles) at INFO level. On a host with several GPU cards and multiple mdev types, this produces very large log output on every cyborg-agent sync cycle.\n\n**Severity**: WARNING | **Confidence**: 0.8\n\n**Impact**: Excessive log volume on every agent sync cycle in production. Makes logs harder to search, wastes disk, and potentially impacts performance when formatting large object graphs.\n\n**Suggestion**:\nChange LOG.info to LOG.debug for the full device list, or replace with a count-based summary like LOG.info(\u0027Discovered %d mdev device(s)\u0027, len(device_list)).","commit_id":"0a011c7c28536b3b02f7dc8b954a20c475bc92df"},{"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":"43fedf8085419e273823f8a64b64355d0ccef6ad","unresolved":false,"context_lines":[{"line_number":117,"context_line":"                raise exception.PciConfigInvalidWhitelist("},{"line_number":118,"context_line":"                    reason\u003df\u0027Invalid mdev device_spec entry: {spec_str}\u0027"},{"line_number":119,"context_line":"                )"},{"line_number":120,"context_line":"            if not isinstance(spec, dict):"},{"line_number":121,"context_line":"                raise exception.PciConfigInvalidWhitelist("},{"line_number":122,"context_line":"                    reason\u003df\u0027mdev device_spec entry is not a dict: {spec_str}\u0027"},{"line_number":123,"context_line":"                )"}],"source_content_type":"text/x-python","patch_set":7,"id":"a4fbe380_88a0b6f2","line":120,"updated":"2026-07-22 15:48:13.000000000","message":"The _parse_device_specs method includes a guard that raises PciConfigInvalidWhitelist when a JSON entry parses to a non-dict type (e.g., a list or number), but no unit test exercises this code path. Tests exist for invalid JSON strings and for dicts missing required keys, but not for valid JSON t...\n\n**Severity**: SUGGESTION | **Confidence**: 0.8\n\n**Benefit**: An untested code path could harbor regressions if the guard logic changes. Currently the guard is simple and likely correct, but a test would provide confidence and documentation of the expected behavior.\n\n**Recommendation**:\nAdd a test in test_driver.py that sets device_spec to a JSON array or number string (e.g., \u0027[1, 2, 3]\u0027) and asserts that PciConfigInvalidWhitelist is raised, mirroring the existing test_invalid_json_device_spec_raises pattern.","commit_id":"58abc9a63cde28c004b4211adab98065b8b19e3f"},{"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":"e88566f0224e32839a81fa43ad79cdae95e3f047","unresolved":false,"context_lines":[{"line_number":216,"context_line":"        :returns: Resource class string."},{"line_number":217,"context_line":"        \"\"\""},{"line_number":218,"context_line":"        rc \u003d spec.get(\u0027resource_class\u0027)"},{"line_number":219,"context_line":"        rc_name \u003d rc.replace(\u0027CUSTOM_\u0027, \u0027\u0027) if rc else \u0027MDEV_\u0027 + type_name"},{"line_number":220,"context_line":"        return orc.normalize_name(rc_name)"},{"line_number":221,"context_line":""},{"line_number":222,"context_line":"    def _get_traits("}],"source_content_type":"text/x-python","patch_set":8,"id":"c0263235_6e31a029","line":219,"updated":"2026-07-29 11:31:37.000000000","message":"Both _get_resource_class and _get_traits use str.replace(\u0027CUSTOM_\u0027, \u0027\u0027) to strip the CUSTOM_ namespace prefix before passing the result to normalize_name. str.replace removes every occurrence of the substring, not just a leading prefix. If an operator specifies a resource_class or trait name cont...\n\n**Severity**: SUGGESTION | **Confidence**: 0.8\n\n**Benefit**: An operator who specifies a resource_class or trait containing an embedded \u0027CUSTOM_\u0027 substring will get a different Placement resource class or trait than intended, leading to incorrect resource reporting. The issue is silent (no error or warning) so it would be hard to diagnose.\n\n**Recommendation**:\nUse str.removeprefix(\u0027CUSTOM_\u0027) (available since Python 3.9, project minimum is 3.10) instead of str.replace(\u0027CUSTOM_\u0027, \u0027\u0027) in both _get_resource_class and _get_traits to strip only the leading prefix. For example: rc.removeprefix(\u0027CUSTOM_\u0027) and trait.removeprefix(\u0027CUSTOM_\u0027).","commit_id":"542bea5c51135fe14517e052054cb8a40adc7bb3"},{"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":"659919f2c4f8663f78f0841599928a82e1d491db","unresolved":false,"context_lines":[{"line_number":234,"context_line":"                extra,"},{"line_number":235,"context_line":"            )"},{"line_number":236,"context_line":"            extra \u003d []"},{"line_number":237,"context_line":"        extra_traits \u003d ["},{"line_number":238,"context_line":"            os_traits.normalize_name(trait.removeprefix(\u0027CUSTOM_\u0027))"},{"line_number":239,"context_line":"            for trait in extra"},{"line_number":240,"context_line":"        ]"}],"source_content_type":"text/x-python","patch_set":10,"id":"bea6827e_f73a0746","line":237,"updated":"2026-07-30 11:55:22.000000000","message":"The _get_traits method validates that the \u0027traits\u0027 config value is a list, but individual list entries are not type-checked before calling str.removeprefix in the list comprehension. If an operator configures a traits list containing non-string values (e.g., a number or JSON null), the code will...\n\n**Severity**: SUGGESTION | **Confidence**: 0.8\n\n**Benefit**: If an operator mistakenly includes a non-string trait value in the device_spec JSON (e.g., {\"traits\": [\"CUSTOM_FAST\", 123]}), discovery will crash with AttributeError instead of gracefully skipping the invalid entry. This makes the driver fragile against minor configuration errors.\n\n**Recommendation**:\nAdd a type check or try/except for individual trait entries before calling removeprefix. For example: filter out non-string entries with a warning log, or wrap each normalize_name call in a try/except.","commit_id":"8f372aaf8c2d6bbeeffc338aeb24f71102e5d8b2"},{"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":"a6baa37ca5d20fdff5f1ebca2a1e4dbda7d4b323","unresolved":false,"context_lines":[{"line_number":350,"context_line":"                    ),"},{"line_number":351,"context_line":"                )"},{"line_number":352,"context_line":""},{"line_number":353,"context_line":"        LOG.info(\u0027mdev device_list: %s\u0027, device_list)"},{"line_number":354,"context_line":"        return device_list"}],"source_content_type":"text/x-python","patch_set":12,"id":"840dff99_5385cb03","line":353,"updated":"2026-08-03 08:55:42.000000000","message":"The discover() method calls LOG.info with the entire device_list, which contains DriverDevice VersionedObjects with deeply nested deployables and attach handles. Since discover() is called periodically by the cyborg-agent, this can produce significant log volume in production environments with ma...\n\n**Severity**: WARNING | **Confidence**: 0.8\n\n**Impact**: Excessive INFO-level logging of serialized VersionedObject lists on every periodic discovery cycle. In production with many devices, this floods logs with multi-line object dumps that are difficult to filter and consume disk space.\n\n**Suggestion**:\nChange LOG.info to LOG.debug, or log only a summary (e.g., device count and PCI addresses) at INFO while reserving the full object dump for DEBUG level.","commit_id":"a2df176291092377ef4823301c21d1160b92a518"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"8e0c49e1f5993a563404d09a8a82e1f2b9176b7e","unresolved":true,"context_lines":[{"line_number":140,"context_line":"        driver_ah \u003d driver_attach_handle.DriverAttachHandle()"},{"line_number":141,"context_line":"        driver_ah.in_use \u003d False"},{"line_number":142,"context_line":"        driver_ah.attach_type \u003d constants.AH_TYPE_MDEV"},{"line_number":143,"context_line":"        vgpu_mark \u003d type_name + \u0027_\u0027 + str(num)"},{"line_number":144,"context_line":"        driver_ah.attach_info \u003d utils.mdev_str_to_json("},{"line_number":145,"context_line":"            pci_address,"},{"line_number":146,"context_line":"            type_name,"}],"source_content_type":"text/x-python","patch_set":13,"id":"b8c79cbf_f069a93c","line":143,"range":{"start_line":143,"start_character":7,"end_line":143,"end_character":12},"updated":"2026-08-04 19:14:14.000000000","message":"this is a generic mdev driver\nwe shoudl not use the term gpu anywher in it\n\nwe do not wnat to assuem these device are gpus","commit_id":"1f7a750474ba150cf2c325b3623b89d53853fbdb"},{"author":{"_account_id":34452,"name":"Joan Gilabert","display_name":"jgilaber","email":"jgilaber@redhat.com","username":"jgilaber"},"change_message_id":"77d749f28b646667ebda9edf06351324026cc904","unresolved":false,"context_lines":[{"line_number":140,"context_line":"        driver_ah \u003d driver_attach_handle.DriverAttachHandle()"},{"line_number":141,"context_line":"        driver_ah.in_use \u003d False"},{"line_number":142,"context_line":"        driver_ah.attach_type \u003d constants.AH_TYPE_MDEV"},{"line_number":143,"context_line":"        vgpu_mark \u003d type_name + \u0027_\u0027 + str(num)"},{"line_number":144,"context_line":"        driver_ah.attach_info \u003d utils.mdev_str_to_json("},{"line_number":145,"context_line":"            pci_address,"},{"line_number":146,"context_line":"            type_name,"}],"source_content_type":"text/x-python","patch_set":13,"id":"ca17b09e_d3d58f9a","line":143,"range":{"start_line":143,"start_character":7,"end_line":143,"end_character":12},"in_reply_to":"b8c79cbf_f069a93c","updated":"2026-08-31 12:33:24.000000000","message":"Done","commit_id":"1f7a750474ba150cf2c325b3623b89d53853fbdb"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"8e0c49e1f5993a563404d09a8a82e1f2b9176b7e","unresolved":true,"context_lines":[{"line_number":161,"context_line":"        :returns: Resource class string."},{"line_number":162,"context_line":"        \"\"\""},{"line_number":163,"context_line":"        rc \u003d spec.resource_class"},{"line_number":164,"context_line":"        rc_name \u003d rc.removeprefix(\u0027CUSTOM_\u0027) if rc else \u0027MDEV_\u0027 + type_name"},{"line_number":165,"context_line":"        return orc.normalize_name(rc_name)"},{"line_number":166,"context_line":""},{"line_number":167,"context_line":"    def _get_traits(self, spec):"}],"source_content_type":"text/x-python","patch_set":13,"id":"31d41198_9b7fe1da","line":164,"range":{"start_line":164,"start_character":34,"end_line":164,"end_character":43},"updated":"2026-08-04 19:14:14.000000000","message":"nit: we should factor this out into a shared constant","commit_id":"1f7a750474ba150cf2c325b3623b89d53853fbdb"},{"author":{"_account_id":34452,"name":"Joan Gilabert","display_name":"jgilaber","email":"jgilaber@redhat.com","username":"jgilaber"},"change_message_id":"77d749f28b646667ebda9edf06351324026cc904","unresolved":false,"context_lines":[{"line_number":161,"context_line":"        :returns: Resource class string."},{"line_number":162,"context_line":"        \"\"\""},{"line_number":163,"context_line":"        rc \u003d spec.resource_class"},{"line_number":164,"context_line":"        rc_name \u003d rc.removeprefix(\u0027CUSTOM_\u0027) if rc else \u0027MDEV_\u0027 + type_name"},{"line_number":165,"context_line":"        return orc.normalize_name(rc_name)"},{"line_number":166,"context_line":""},{"line_number":167,"context_line":"    def _get_traits(self, spec):"}],"source_content_type":"text/x-python","patch_set":13,"id":"198d1e6e_23294f1b","line":164,"range":{"start_line":164,"start_character":34,"end_line":164,"end_character":43},"in_reply_to":"31d41198_9b7fe1da","updated":"2026-08-31 12:33:24.000000000","message":"Done","commit_id":"1f7a750474ba150cf2c325b3623b89d53853fbdb"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"8e0c49e1f5993a563404d09a8a82e1f2b9176b7e","unresolved":true,"context_lines":[{"line_number":318,"context_line":"        LOG.info(\u0027Discovered %d mdev parent device(s)\u0027, len(parents))"},{"line_number":319,"context_line":""},{"line_number":320,"context_line":"        device_list \u003d []"},{"line_number":321,"context_line":"        hostname \u003d CONF.host"},{"line_number":322,"context_line":"        for parent in parents:"},{"line_number":323,"context_line":"            pci_address \u003d parent.address"},{"line_number":324,"context_line":"            mdev_types \u003d self._bus_manager.get_mdev_types("}],"source_content_type":"text/x-python","patch_set":13,"id":"7845406d_0904a0a8","line":321,"range":{"start_line":321,"start_character":8,"end_line":321,"end_character":28},"updated":"2026-08-04 19:14:14.000000000","message":"this kind of problematic.\n\nthe name of the resouce provider  should be  prefixed with the hypervior_hostnaem which cannot be assumed to be  CONF.host\n\nhttps://github.com/openstack/cyborg/blob/master/cyborg/conf/default.py#L40-L50\n\nwe shoudl use\n\n`CONF.agent.resource_provider_name` \n\nwhich default to socket.getfqdn() instead of socket.gethostname()\n\nhttps://github.com/openstack/cyborg/blob/master/cyborg/conf/agent.py#L45-L57\n\nsocket.getfqdn() more closely matches libvirts hostname behvior then socket.gethostname()\n\nlibvirt really tries to prefer the fqdn if it can find it and has a 3 level fallback to find it and socket.gethostname() is effectivly the first stagey that it tires but its not the same\n\nanyway we should be using CONF.agent.resource_provider_name for the root resouce provider name\n\ni guess i didnt fix that in the nested provider names when i fixed the agent startup bug last cycle.\n\nfor now we can continue to use this but we may want to fix this in the future as a follow up to \n\nhttps://github.com/openstack/cyborg/commit/0e9a632f3165af8d108301d7838ba2792de64222\n\nthe compute manager shoudl really passin the rp name to the drivers when its creatin the driver.\n\n\ntechnially the root provider name and nested prodivcer dont need to be related in any way we just need to ensure we dont have name collisions.\n\nhaving them be related is just for humans to grok","commit_id":"1f7a750474ba150cf2c325b3623b89d53853fbdb"},{"author":{"_account_id":34452,"name":"Joan Gilabert","display_name":"jgilaber","email":"jgilaber@redhat.com","username":"jgilaber"},"change_message_id":"77d749f28b646667ebda9edf06351324026cc904","unresolved":true,"context_lines":[{"line_number":318,"context_line":"        LOG.info(\u0027Discovered %d mdev parent device(s)\u0027, len(parents))"},{"line_number":319,"context_line":""},{"line_number":320,"context_line":"        device_list \u003d []"},{"line_number":321,"context_line":"        hostname \u003d CONF.host"},{"line_number":322,"context_line":"        for parent in parents:"},{"line_number":323,"context_line":"            pci_address \u003d parent.address"},{"line_number":324,"context_line":"            mdev_types \u003d self._bus_manager.get_mdev_types("}],"source_content_type":"text/x-python","patch_set":13,"id":"70d9d5db_1203608e","line":321,"range":{"start_line":321,"start_character":8,"end_line":321,"end_character":28},"in_reply_to":"7845406d_0904a0a8","updated":"2026-08-31 12:33:24.000000000","message":"good point, I carried this from other drivers, would be good to fix in all at once","commit_id":"1f7a750474ba150cf2c325b3623b89d53853fbdb"}],"cyborg/common/exception.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":"bad24d3d09e864fd6c63a128662b65e28d36aa41","unresolved":false,"context_lines":[{"line_number":466,"context_line":"    _msg_fmt \u003d _(\"Invalid PCI devices whitelist config: %(reason)s.\")"},{"line_number":467,"context_line":""},{"line_number":468,"context_line":""},{"line_number":469,"context_line":"class InvalidDevSpecConfig(Invalid):"},{"line_number":470,"context_line":"    _msg_fmt \u003d _(\"Invalid DevSpec config: %(reason)s.\")"},{"line_number":471,"context_line":""},{"line_number":472,"context_line":""}],"source_content_type":"text/x-python","patch_set":15,"id":"5bbf8acf_f5927282","line":469,"updated":"2026-08-31 15:24:13.000000000","message":"The commit adds both InvalidDevSpecConfig and InvalidMdevDevSpecConfig to cyborg/common/exception.py, but only InvalidMdevDevSpecConfig is ever raised (from devspec.py); InvalidDevSpecConfig has no producer or consumer anywhere in the tree, including tests.\n\n**Severity**: SUGGESTION | **Confidence**: 0.85\n\n**Impact**: A dead public exception in the shared exception module suggests a supported config-validation path that does not exist and must be kept consistent by future refactors that will never exercise it.\n\n**Recommendation**:\nEither drop InvalidDevSpecConfig from this change, or make InvalidMdevDevSpecConfig subclass it so the base is the real, used parent of the mdev-specific error.","commit_id":"f33ad997ed7dfccdf0d0a8c8a036bdf5a2e2a48c"}],"cyborg/tests/unit/accelerator/drivers/mdev/test_devspec.py":[{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"8e0c49e1f5993a563404d09a8a82e1f2b9176b7e","unresolved":true,"context_lines":[{"line_number":17,"context_line":"from cyborg.tests import base"},{"line_number":18,"context_line":""},{"line_number":19,"context_line":""},{"line_number":20,"context_line":"class TestMdevDeviceSpec(base.TestCase):"},{"line_number":21,"context_line":"    \"\"\"Tests for MdevDeviceSpec construction and validation.\"\"\""},{"line_number":22,"context_line":""},{"line_number":23,"context_line":"    def test_basic_construction(self):"}],"source_content_type":"text/x-python","patch_set":13,"id":"a59555d1_b8674841","line":20,"updated":"2026-08-04 19:14:14.000000000","message":"these will have to be updated as we are far to leanent with invalid config","commit_id":"1f7a750474ba150cf2c325b3623b89d53853fbdb"},{"author":{"_account_id":34452,"name":"Joan Gilabert","display_name":"jgilaber","email":"jgilaber@redhat.com","username":"jgilaber"},"change_message_id":"77d749f28b646667ebda9edf06351324026cc904","unresolved":false,"context_lines":[{"line_number":17,"context_line":"from cyborg.tests import base"},{"line_number":18,"context_line":""},{"line_number":19,"context_line":""},{"line_number":20,"context_line":"class TestMdevDeviceSpec(base.TestCase):"},{"line_number":21,"context_line":"    \"\"\"Tests for MdevDeviceSpec construction and validation.\"\"\""},{"line_number":22,"context_line":""},{"line_number":23,"context_line":"    def test_basic_construction(self):"}],"source_content_type":"text/x-python","patch_set":13,"id":"786cdf5a_4edb728e","line":20,"in_reply_to":"a59555d1_b8674841","updated":"2026-08-31 12:33:24.000000000","message":"Done","commit_id":"1f7a750474ba150cf2c325b3623b89d53853fbdb"}],"cyborg/tests/unit/accelerator/drivers/mdev/test_driver.py":[{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"8e0c49e1f5993a563404d09a8a82e1f2b9176b7e","unresolved":true,"context_lines":[{"line_number":93,"context_line":""},{"line_number":94,"context_line":"        :param specs: List of JSON-encoded device_spec entries."},{"line_number":95,"context_line":"        \"\"\""},{"line_number":96,"context_line":"        self.config(device_spec\u003dspecs, group\u003d\u0027mdev\u0027)"},{"line_number":97,"context_line":""},{"line_number":98,"context_line":"    def _make_driver(self):"},{"line_number":99,"context_line":"        \"\"\"Create a GenericMdevDriver with test paths."}],"source_content_type":"text/x-python","patch_set":13,"id":"566af22f_a7bdd0eb","line":96,"range":{"start_line":96,"start_character":0,"end_line":96,"end_character":52},"updated":"2026-08-04 19:14:14.000000000","message":"you should be using self.flags here\n\nhttps://github.com/openstack/cyborg/blob/master/cyborg/tests/base.py#L65-L69\n\nthe both do mostly the same thing bug mucell memory makes me want to use flags instead\n\nhttps://github.com/openstack/cyborg/blob/65c76dc8188a2c0d6c838751c92395b0e660c8b2/cyborg/tests/unit/accelerator/drivers/pci/pci/test_sysinfo.py#L152\n\nand \nhttps://github.com/openstack/cyborg/blob/65c76dc8188a2c0d6c838751c92395b0e660c8b2/cyborg/tests/base.py#L54\nare the only curren usage of self.config and i would prefer to remove it in the future and only keep self.flags\n\n\nset_defaults alslo shoudl be replaced with self.flags\n\nwe shoudl be using set_override rather then change the default or direcly overriding the config option","commit_id":"1f7a750474ba150cf2c325b3623b89d53853fbdb"},{"author":{"_account_id":34452,"name":"Joan Gilabert","display_name":"jgilaber","email":"jgilaber@redhat.com","username":"jgilaber"},"change_message_id":"77d749f28b646667ebda9edf06351324026cc904","unresolved":false,"context_lines":[{"line_number":93,"context_line":""},{"line_number":94,"context_line":"        :param specs: List of JSON-encoded device_spec entries."},{"line_number":95,"context_line":"        \"\"\""},{"line_number":96,"context_line":"        self.config(device_spec\u003dspecs, group\u003d\u0027mdev\u0027)"},{"line_number":97,"context_line":""},{"line_number":98,"context_line":"    def _make_driver(self):"},{"line_number":99,"context_line":"        \"\"\"Create a GenericMdevDriver with test paths."}],"source_content_type":"text/x-python","patch_set":13,"id":"2c4cb784_b17d3e7f","line":96,"range":{"start_line":96,"start_character":0,"end_line":96,"end_character":52},"in_reply_to":"566af22f_a7bdd0eb","updated":"2026-08-31 12:33:24.000000000","message":"Done","commit_id":"1f7a750474ba150cf2c325b3623b89d53853fbdb"}],"pyproject.toml":[{"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":"7c96ba83670a64b45538690f46ab456dec824219","unresolved":false,"context_lines":[{"line_number":61,"context_line":"intel_nic_driver \u003d \"cyborg.accelerator.drivers.nic.intel.driver:IntelNICDriver\""},{"line_number":62,"context_line":"inspur_nvme_ssd_driver \u003d \"cyborg.accelerator.drivers.ssd.inspur.driver:InspurNVMeSSDDriver\""},{"line_number":63,"context_line":"pci_driver \u003d \"cyborg.accelerator.drivers.pci.pci.driver:PCIDriver\""},{"line_number":64,"context_line":"mdev_driver \u003d \"cyborg.accelerator.drivers.mdev.driver:GenericMdevDriver\""},{"line_number":65,"context_line":""},{"line_number":66,"context_line":"[tool.setuptools.packages.find]"},{"line_number":67,"context_line":"# pci-sim/ is an out-of-tree kernel module and must not be packaged in"}],"source_content_type":"text/x-toml","patch_set":14,"id":"21362433_29b617d5","line":64,"updated":"2026-08-31 12:57:50.000000000","message":"The commit registers the \u0027mdev_driver\u0027 entry point in pyproject.toml, but doc/source/configuration/drivers.rst, the operator-facing reference that lists every available driver with its entry-point name and hardware description, is not updated. The doc explicitly states \u0027The driver names correspond to entry points defined in the Cyborg package\u0027 and lists all drivers including the recently added \u0027pci_driver\u0027; the agent\u0027s enabled_drivers help also steers users to this naming. Without an entry, operators cannot discover that mdev_driver exists or how to enable it with [agent] enabled_drivers.\n\n**Severity**: WARNING | **Confidence**: 0.85\n\n**Impact**: Operators reading the configuration guide will not know the driver exists or how to enable it, limiting adoption of the new feature; support questions and misconfiguration are the likely outcome.\n\n**Suggestion**:\nAdd a \u0027mdev_driver\u0027 row to the table in doc/source/configuration/drivers.rst (name, \u0027Generic mediated device (mdev) driver\u0027, hardware \u0027mdev-capable PCI devices\u0027) and a short section with an example enabled_drivers and [mdev] device_spec configuration, matching the style used for pci_driver.","commit_id":"606e150380a27c914e54712bf539398105d2b5bb"},{"author":{"_account_id":34452,"name":"Joan Gilabert","display_name":"jgilaber","email":"jgilaber@redhat.com","username":"jgilaber"},"change_message_id":"c2308a4e3d916eed8a5b7e18dc7571f7e88ee0c6","unresolved":false,"context_lines":[{"line_number":61,"context_line":"intel_nic_driver \u003d \"cyborg.accelerator.drivers.nic.intel.driver:IntelNICDriver\""},{"line_number":62,"context_line":"inspur_nvme_ssd_driver \u003d \"cyborg.accelerator.drivers.ssd.inspur.driver:InspurNVMeSSDDriver\""},{"line_number":63,"context_line":"pci_driver \u003d \"cyborg.accelerator.drivers.pci.pci.driver:PCIDriver\""},{"line_number":64,"context_line":"mdev_driver \u003d \"cyborg.accelerator.drivers.mdev.driver:GenericMdevDriver\""},{"line_number":65,"context_line":""},{"line_number":66,"context_line":"[tool.setuptools.packages.find]"},{"line_number":67,"context_line":"# pci-sim/ is an out-of-tree kernel module and must not be packaged in"}],"source_content_type":"text/x-toml","patch_set":14,"id":"3323d672_e4bb9218","line":64,"in_reply_to":"21362433_29b617d5","updated":"2026-08-31 13:45:44.000000000","message":"this is done in a later patch https://review.opendev.org/c/openstack/cyborg/+/997053","commit_id":"606e150380a27c914e54712bf539398105d2b5bb"}]}
