)]}'
{"/PATCHSET_LEVEL":[{"author":{"_account_id":30002,"name":"Douglas Viroel","email":"viroel@gmail.com","username":"dviroel"},"change_message_id":"2b1d6b3368d53f1f70d22dac21bd1cbd56191c99","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":1,"id":"c90822b1_43e59e79","updated":"2026-06-18 18:46:15.000000000","message":"-1: more nits than issues I think","commit_id":"1b42cb1522e89533b652e6fd19aec6f44519db0f"},{"author":{"_account_id":34452,"name":"Joan Gilabert","display_name":"jgilaber","email":"jgilaber@redhat.com","username":"jgilaber"},"change_message_id":"7f6c366c550e7a20b6d09b624f2612150170d504","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":1,"id":"63d74a20_1a508b2a","updated":"2026-06-03 07:12:08.000000000","message":"check-rdo failed while installing openstack","commit_id":"1b42cb1522e89533b652e6fd19aec6f44519db0f"},{"author":{"_account_id":34452,"name":"Joan Gilabert","display_name":"jgilaber","email":"jgilaber@redhat.com","username":"jgilaber"},"change_message_id":"80fb7334f810afb67dd78134953ab77331e17d40","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":1,"id":"63af04ce_90c8e588","updated":"2026-06-04 15:16:46.000000000","message":"check-rdo job is fixed","commit_id":"1b42cb1522e89533b652e6fd19aec6f44519db0f"},{"author":{"_account_id":16312,"name":"Alfredo Moralejo","email":"amoralej@redhat.com","username":"amoralej"},"change_message_id":"e090a386269d03ae95923da0471bf5de296fc957","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":5,"id":"0ea2d9f7_5b470701","updated":"2026-06-23 11:23:59.000000000","message":"recheck","commit_id":"5d4682dc9de284af28879fd7ecd5d3b33b691286"},{"author":{"_account_id":16312,"name":"Alfredo Moralejo","email":"amoralej@redhat.com","username":"amoralej"},"change_message_id":"05459bf29fa1a64f6e227740f1ffd9d39925f665","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":5,"id":"776f01cc_966e4058","updated":"2026-06-22 12:04:55.000000000","message":"recheck","commit_id":"5d4682dc9de284af28879fd7ecd5d3b33b691286"}],"devstack/lib/watcher":[{"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":"e926588bfe40e5c53de9bf98bf23d0c17103a6f1","unresolved":false,"context_lines":[{"line_number":155,"context_line":"    configure_keystone_authtoken_middleware $WATCHER_CONF watcher \"watcher_clients_auth\""},{"line_number":156,"context_line":"    configure_keystoneauth $WATCHER_CONF watcher \"nova\""},{"line_number":157,"context_line":"    configure_keystoneauth $WATCHER_CONF watcher \"keystone\""},{"line_number":158,"context_line":"    configure_keystoneauth $WATCHER_CONF watcher placement"},{"line_number":159,"context_line":""},{"line_number":160,"context_line":"    if [ -n \"$WATCHER_STATE_PATH\" ]; then"},{"line_number":161,"context_line":"        iniset $WATCHER_CONF DEFAULT state_path \"$WATCHER_STATE_PATH\""}],"source_content_type":"application/octet-stream","patch_set":4,"id":"f09b0cfe_62e5f16a","line":158,"updated":"2026-06-19 10:35:57.000000000","message":"In devstack/lib/watcher, the new configure_keystoneauth call passes placement without quotes while all other similar calls in the same block use quoted strings.\n\n**Severity**: SUGGESTION | **Confidence**: 0.9\n\n**Benefit**: Consistency with the surrounding code style and avoidance of potential word-splitting issues if the argument were ever changed to contain spaces.\n\n**Recommendation**:\nChange to: configure_keystoneauth $WATCHER_CONF watcher \"placement\"","commit_id":"2d9058323e4dad65c806b5b955021754baed9c85"}],"releasenotes/notes/placement-openstacksdk-migration-538668b56ef90196.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":"694d7cb54669e60b39979afa426024c9a8d594c4","unresolved":false,"context_lines":[{"line_number":6,"context_line":"    instead of ``[placement_client]``."},{"line_number":7,"context_line":"deprecations:"},{"line_number":8,"context_line":"  - |"},{"line_number":9,"context_line":"    The ``[placement_client]`` configuration options are deprecated and"},{"line_number":10,"context_line":"    will be removed in a future release. Operators should migrate to the"},{"line_number":11,"context_line":"    keystoneauth adapter configuration options in the ``[placement]``"},{"line_number":12,"context_line":"    configuration group."}],"source_content_type":"text/x-yaml","patch_set":5,"id":"48d64607_9121151a","line":9,"updated":"2026-06-19 11:12:49.000000000","message":"The release note mentions [placement_client] options will be removed in a future release but does not specify which release. Other deprecation annotations in the same patch use deprecated_since\u003d\u00272026.2\u0027 without a removal target\n\n**Severity**: SUGGESTION | **Confidence**: 0.7\n\n**Benefit**: Operators need a concrete removal target to plan their migration timeline\n\n**Recommendation**:\nSpecify the target removal release in the deprecation note, e.g. \u0027will be removed in the 2027.1 release\u0027 or follow the OpenStack standard SLA of deprecating in N and removing in N+2","commit_id":"5d4682dc9de284af28879fd7ecd5d3b33b691286"}],"watcher/common/placement_helper.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":"e926588bfe40e5c53de9bf98bf23d0c17103a6f1","unresolved":false,"context_lines":[{"line_number":56,"context_line":""},{"line_number":57,"context_line":"class PlacementHelper(BaseConnectionMixin):"},{"line_number":58,"context_line":"    def __init__(self, session\u003dNone, context\u003dNone):"},{"line_number":59,"context_line":"        \"\"\"Create and return a helper to call the placement service"},{"line_number":60,"context_line":""},{"line_number":61,"context_line":"        :param session: Optional keystone session to create the openstack"},{"line_number":62,"context_line":"        connection."}],"source_content_type":"text/x-python","patch_set":4,"id":"052fb8b5_37e5e248","line":59,"updated":"2026-06-19 10:35:57.000000000","message":"The PlacementHelper.__init__ docstring says \u0027Create and return a helper\u0027 but __init__ methods do not return anything. The wording should say \u0027Initialize\u0027 or \u0027Create\u0027 instead of \u0027Create and return\u0027.\n\n**Severity**: SUGGESTION | **Confidence**: 0.9\n\n**Benefit**: More accurate documentation that matches the method semantics.\n\n**Recommendation**:\nChange to: \u0027\u0027\u0027Initialize a helper to call the placement service.\u0027\u0027\u0027 to match the NovaHelper.__init__ docstring pattern.","commit_id":"2d9058323e4dad65c806b5b955021754baed9c85"},{"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":"e926588bfe40e5c53de9bf98bf23d0c17103a6f1","unresolved":false,"context_lines":[{"line_number":82,"context_line":"                inv.resource_class: Inventory.from_openstacksdk(inv)"},{"line_number":83,"context_line":"                for inv in invs"},{"line_number":84,"context_line":"            }"},{"line_number":85,"context_line":"        except (sdk_exc.NotFoundException, sdk_exc.SDKException) as exc:"},{"line_number":86,"context_line":"            LOG.exception(exc)"},{"line_number":87,"context_line":"            return None"}],"source_content_type":"text/x-python","patch_set":4,"id":"90a6e558_67991910","line":85,"updated":"2026-06-19 10:35:57.000000000","message":"The except clause catches both sdk_exc.NotFoundException and sdk_exc.SDKException, but NotFoundException is a subclass of SDKException, making the explicit NotFoundException catch redundant. More importantly, catching the broad SDKException silently returns None for all SDK errors including connection failures, auth errors, and HTTP errors.\n\n**Severity**: WARNING | **Confidence**: 0.9\n\n**Impact**: Transient connection errors, authentication failures, or unexpected HTTP errors (e.g., 500) will be silently swallowed and treated the same as a 404, returning None. This could mask infrastructure problems and make debugging difficult in production.\n\n**Suggestion**:\nCatch only sdk_exc.NotFoundException for the None-return path. For other SDKException subclasses, either re-raise or log at ERROR level with more context (e.g., \u0027Failed to get inventories for resource provider %s\u0027). Consider whether callers can distinguish between \u0027not found\u0027 and \u0027service error\u0027.","commit_id":"2d9058323e4dad65c806b5b955021754baed9c85"},{"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":"e926588bfe40e5c53de9bf98bf23d0c17103a6f1","unresolved":false,"context_lines":[{"line_number":83,"context_line":"                for inv in invs"},{"line_number":84,"context_line":"            }"},{"line_number":85,"context_line":"        except (sdk_exc.NotFoundException, sdk_exc.SDKException) as exc:"},{"line_number":86,"context_line":"            LOG.exception(exc)"},{"line_number":87,"context_line":"            return None"}],"source_content_type":"text/x-python","patch_set":4,"id":"f59ef66d_7283e4ea","line":86,"updated":"2026-06-19 10:35:57.000000000","message":"The LOG.exception(exc) call passes the exception object as the log message rather than providing human-readable context about which operation failed and for which resource provider.\n\n**Severity**: WARNING | **Confidence**: 0.8\n\n**Impact**: Log entries will contain the raw exception repr without context about what Watcher was doing (e.g., which rp_uuid was queried). This makes log analysis and incident response harder.\n\n**Suggestion**:\nUse a descriptive message with the rp_uuid for context, e.g.: LOG.exception(\u0027Failed to get inventories for resource provider %s\u0027, rp_uuid). While LOG.exception(exc) is an existing pattern in this codebase, adding context is especially valuable here since the same exception type can occur for different rp_uuids.","commit_id":"2d9058323e4dad65c806b5b955021754baed9c85"},{"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":"694d7cb54669e60b39979afa426024c9a8d594c4","unresolved":false,"context_lines":[{"line_number":1,"context_line":"# Licensed under the Apache License, Version 2.0 (the \"License\");"},{"line_number":2,"context_line":"# you may not use this file except in compliance with the License."},{"line_number":3,"context_line":"# You may obtain a copy of the License at"},{"line_number":4,"context_line":"#"}],"source_content_type":"text/x-python","patch_set":5,"id":"5ebf53af_f0f547ff","line":1,"updated":"2026-06-19 11:12:49.000000000","message":"Missing module docstring in placement_helper.py - the comprehensive style guide requires a module docstring after the license header, and ruff format has docstring-code-format enabled\n\n**Severity**: WARNING | **Confidence**: 0.8\n\n**Impact**: Inconsistent with the style guide recommendation. While other helper modules in the codebase also lack module docstrings, new and substantially refactored files should include one\n\n**Suggestion**:\nAdd a module docstring such as: \"\"\"Helper for interacting with the OpenStack Placement service.\"\"\" after the license header and before the imports","commit_id":"5d4682dc9de284af28879fd7ecd5d3b33b691286"},{"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":"694d7cb54669e60b39979afa426024c9a8d594c4","unresolved":false,"context_lines":[{"line_number":37,"context_line":"    step_size: int"},{"line_number":38,"context_line":"    allocation_ratio: float"},{"line_number":39,"context_line":""},{"line_number":40,"context_line":"    @classmethod"},{"line_number":41,"context_line":"    def from_openstacksdk(cls, inventory):"},{"line_number":42,"context_line":"        \"\"\"Create an Inventory from an OpenStackSDK inventory."},{"line_number":43,"context_line":""}],"source_content_type":"text/x-python","patch_set":5,"id":"4ce70502_281271ad","line":40,"updated":"2026-06-19 11:12:49.000000000","message":"The Inventory.from_openstacksdk classmethod accesses SDK object attributes (total, reserved, min_unit, etc.) without validation, which could raise AttributeError if the SDK returns an incomplete object\n\n**Severity**: WARNING | **Confidence**: 0.7\n\n**Impact**: If the OpenStackSDK returns a ResourceProviderInventory with missing attributes (e.g. due to API version differences), from_openstacksdk will raise AttributeError which is caught by the SDKException handler in get_inventories, but the error message will be misleading\n\n**Suggestion**:\nConsider using getattr with defaults in from_openstacksdk, or add type validation. At minimum document that the SDK inventory object must have all six attributes populated","commit_id":"5d4682dc9de284af28879fd7ecd5d3b33b691286"},{"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":"6a99cc9e9934d9e236d2e3091176dd4c7477533e","unresolved":false,"context_lines":[{"line_number":41,"context_line":"    def from_openstacksdk(cls, inventory):"},{"line_number":42,"context_line":"        \"\"\"Create an Inventory from an OpenStackSDK inventory."},{"line_number":43,"context_line":""},{"line_number":44,"context_line":"        :param inventory: openstack.placement.Inventory"},{"line_number":45,"context_line":"        :returns: Inventory dataclass instance"},{"line_number":46,"context_line":"        \"\"\""},{"line_number":47,"context_line":"        return cls("}],"source_content_type":"text/x-python","patch_set":5,"id":"a06e28c2_36076a63","line":44,"updated":"2026-06-23 11:46:11.000000000","message":"The Inventory.from_openstacksdk classmethod docstring references \u0027openstack.placement.Inventory\u0027 but the actual SDK type is openstack.placement.v1.resource_provider_inventory.ResourceProviderInventory.\n\n**Severity**: SUGGESTION | **Confidence**: 0.8\n\n**Benefit**: Accurate type references in docstrings help developers understand the exact SDK contract without inspecting test helpers or SDK source.\n\n**Recommendation**:\nUpdate the :param type reference to match the actual SDK class name, e.g. \u0027:param inventory: ResourceProviderInventory from openstack.placement.v1.resource_provider_inventory\u0027.","commit_id":"5d4682dc9de284af28879fd7ecd5d3b33b691286"},{"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":"694d7cb54669e60b39979afa426024c9a8d594c4","unresolved":false,"context_lines":[{"line_number":67,"context_line":"            \u0027placement\u0027, context\u003dcontext, session\u003dsession"},{"line_number":68,"context_line":"        )"},{"line_number":69,"context_line":""},{"line_number":70,"context_line":"    def get_inventories(self, rp_uuid: str) -\u003e dict[str, Inventory] | None:"},{"line_number":71,"context_line":"        \"\"\"Calls the placement API to get resource inventory information."},{"line_number":72,"context_line":""},{"line_number":73,"context_line":"        :param rp_uuid: UUID of the resource provider to get."}],"source_content_type":"text/x-python","patch_set":5,"id":"826b5ef6_c40b8639","line":70,"updated":"2026-06-19 11:12:49.000000000","message":"The docstring for get_inventories return type says \u0027keyed by resource classes\u0027 but the actual key comes from inv.resource_class which is an SDK attribute - the mapping between the SDK attribute and the orc constants used by callers should be documented\n\n**Severity**: SUGGESTION | **Confidence**: 0.7\n\n**Benefit**: Future maintainers will understand that inv.resource_class returns string values like \u0027VCPU\u0027 that match orc.VCPU constants, avoiding confusion about the key format\n\n**Recommendation**:\nAdd a note to the docstring clarifying that keys are string resource class names (e.g. \u0027VCPU\u0027, \u0027MEMORY_MB\u0027, \u0027DISK_GB\u0027) compatible with os_resource_classes constants","commit_id":"5d4682dc9de284af28879fd7ecd5d3b33b691286"},{"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":"694d7cb54669e60b39979afa426024c9a8d594c4","unresolved":false,"context_lines":[{"line_number":82,"context_line":"                inv.resource_class: Inventory.from_openstacksdk(inv)"},{"line_number":83,"context_line":"                for inv in invs"},{"line_number":84,"context_line":"            }"},{"line_number":85,"context_line":"        except sdk_exc.SDKException as exc:"},{"line_number":86,"context_line":"            LOG.exception(exc)"},{"line_number":87,"context_line":"            return None"}],"source_content_type":"text/x-python","patch_set":5,"id":"71ed9a86_6cfe79bf","line":85,"updated":"2026-06-19 11:12:49.000000000","message":"The get_inventories method catches the broad sdk_exc.SDKException base class. While this matches the pattern used in other helpers, it may mask programming errors such as TypeError or AttributeError that are not related to placement API failures\n\n**Severity**: WARNING | **Confidence**: 0.7\n\n**Impact**: Bugs in the code (e.g. accessing a non-existent attribute on the SDK response) would be silently caught and logged as SDK exceptions, returning None instead of surfacing the actual error\n\n**Suggestion**:\nConsider catching more specific exceptions like sdk_exc.NotFoundException and sdk_exc.HttpException separately, or at minimum add a comment explaining the rationale for catching the base SDKException","commit_id":"5d4682dc9de284af28879fd7ecd5d3b33b691286"},{"author":{"_account_id":30002,"name":"Douglas Viroel","email":"viroel@gmail.com","username":"dviroel"},"change_message_id":"d389401aa1e23b890208527fa774c706b650c9bc","unresolved":false,"context_lines":[{"line_number":82,"context_line":"                inv.resource_class: Inventory.from_openstacksdk(inv)"},{"line_number":83,"context_line":"                for inv in invs"},{"line_number":84,"context_line":"            }"},{"line_number":85,"context_line":"        except sdk_exc.SDKException as exc:"},{"line_number":86,"context_line":"            LOG.exception(exc)"},{"line_number":87,"context_line":"            return None"}],"source_content_type":"text/x-python","patch_set":5,"id":"dceccfc7_9c56a098","line":85,"in_reply_to":"71ed9a86_6cfe79bf","updated":"2026-06-19 19:17:49.000000000","message":"Done","commit_id":"5d4682dc9de284af28879fd7ecd5d3b33b691286"},{"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":"694d7cb54669e60b39979afa426024c9a8d594c4","unresolved":false,"context_lines":[{"line_number":83,"context_line":"                for inv in invs"},{"line_number":84,"context_line":"            }"},{"line_number":85,"context_line":"        except sdk_exc.SDKException as exc:"},{"line_number":86,"context_line":"            LOG.exception(exc)"},{"line_number":87,"context_line":"            return None"}],"source_content_type":"text/x-python","patch_set":5,"id":"06d00383_d59f644b","line":86,"updated":"2026-06-19 11:12:49.000000000","message":"LOG.exception(exc) passes the exception object as the log message argument rather than using lazy %s interpolation, inconsistent with oslo_log best practices and the G (flake8-logging-format) ruff rule selected in pyproject.toml\n\n**Severity**: HIGH | **Confidence**: 0.8\n\n**Risk**: Passing the exception directly as the message may cause the logging formatter to str() the exception, bypassing structured logging and traceback handling that oslo_log provides when using LOG.exception() with no args or a format string\n\n**Priority**: Before merge\n**Why This Matters**: The project explicitly selects ruff rule G (flake8-logging-format) which discourages passing objects directly to log calls. While existing code in other helpers has this pattern, new code should follow best practices\n\n**Recommendation**:\nReplace LOG.exception(exc) with either LOG.exception(\u0027Failed to get inventories for resource provider %s\u0027, rp_uuid) which will automatically include the traceback, or simply LOG.exception() if the context is clear from the function name","commit_id":"5d4682dc9de284af28879fd7ecd5d3b33b691286"},{"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":"6a99cc9e9934d9e236d2e3091176dd4c7477533e","unresolved":false,"context_lines":[{"line_number":83,"context_line":"                for inv in invs"},{"line_number":84,"context_line":"            }"},{"line_number":85,"context_line":"        except sdk_exc.SDKException as exc:"},{"line_number":86,"context_line":"            LOG.exception(exc)"},{"line_number":87,"context_line":"            return None"}],"source_content_type":"text/x-python","patch_set":5,"id":"c05b03d8_8e3f9c53","line":86,"updated":"2026-06-23 11:46:11.000000000","message":"LOG.exception(exc) passes the exception object as the log message instead of a descriptive string, losing the rp_uuid context the old implementation logged (status code, error text, resource provider UUID).\n\n**Severity**: WARNING | **Confidence**: 0.8\n\n**Impact**: When get_inventories fails, operators see only the raw SDK exception without knowing which resource provider UUID was queried, degrading troubleshooting for multi-node placement failures.\n\n**Suggestion**:\nUse a descriptive message with rp_uuid context, e.g.: LOG.exception(\u0027Failed to get inventories for resource provider %s\u0027, rp_uuid). The traceback is appended automatically by LOG.exception().","commit_id":"5d4682dc9de284af28879fd7ecd5d3b33b691286"},{"author":{"_account_id":30002,"name":"Douglas Viroel","email":"viroel@gmail.com","username":"dviroel"},"change_message_id":"d389401aa1e23b890208527fa774c706b650c9bc","unresolved":true,"context_lines":[{"line_number":83,"context_line":"                for inv in invs"},{"line_number":84,"context_line":"            }"},{"line_number":85,"context_line":"        except sdk_exc.SDKException as exc:"},{"line_number":86,"context_line":"            LOG.exception(exc)"},{"line_number":87,"context_line":"            return None"}],"source_content_type":"text/x-python","patch_set":5,"id":"941ebf15_971d611b","line":86,"in_reply_to":"06d00383_d59f644b","updated":"2026-06-19 19:17:49.000000000","message":"I think that is valid point but I would no block because of this. It can be changed in a follow up","commit_id":"5d4682dc9de284af28879fd7ecd5d3b33b691286"}],"watcher/conf/placement.py":[{"author":{"_account_id":16312,"name":"Alfredo Moralejo","email":"amoralej@redhat.com","username":"amoralej"},"change_message_id":"37730747dc1637eaefbc21ec1fd7e947a9b5d667","unresolved":true,"context_lines":[{"line_number":41,"context_line":"    # value (e.g publicURL)"},{"line_number":42,"context_line":"    deprecations \u003d {"},{"line_number":43,"context_line":"        \u0027region_name\u0027: [cfg.DeprecatedOpt(\u0027region_name\u0027, \u0027placement_client\u0027)],"},{"line_number":44,"context_line":"        \u0027interface\u0027: [cfg.DeprecatedOpt(\u0027interface\u0027, \u0027placement_client\u0027)],"},{"line_number":45,"context_line":"    }"},{"line_number":46,"context_line":"    return deprecations"},{"line_number":47,"context_line":""}],"source_content_type":"text/x-python","patch_set":3,"id":"1b3c8fa4_49bad3ff","line":44,"range":{"start_line":44,"start_character":0,"end_line":44,"end_character":2},"updated":"2026-06-19 09:54:25.000000000","message":"interface is not a keystone session option, shouldn\u0027t this be something like https://github.com/openstack/watcher/blob/master/watcher/conf/keystone.py#L28-L30 ?","commit_id":"646724637f0942ce46a02c37480c32a807c9e7f8"},{"author":{"_account_id":34452,"name":"Joan Gilabert","display_name":"jgilaber","email":"jgilaber@redhat.com","username":"jgilaber"},"change_message_id":"965506cdfba690570183b81e18d4a350c98d5687","unresolved":true,"context_lines":[{"line_number":41,"context_line":"    # value (e.g publicURL)"},{"line_number":42,"context_line":"    deprecations \u003d {"},{"line_number":43,"context_line":"        \u0027region_name\u0027: [cfg.DeprecatedOpt(\u0027region_name\u0027, \u0027placement_client\u0027)],"},{"line_number":44,"context_line":"        \u0027interface\u0027: [cfg.DeprecatedOpt(\u0027interface\u0027, \u0027placement_client\u0027)],"},{"line_number":45,"context_line":"    }"},{"line_number":46,"context_line":"    return deprecations"},{"line_number":47,"context_line":""}],"source_content_type":"text/x-python","patch_set":3,"id":"7b511750_2911d96e","line":44,"range":{"start_line":44,"start_character":0,"end_line":44,"end_character":2},"in_reply_to":"1b3c8fa4_49bad3ff","updated":"2026-06-19 10:50:02.000000000","message":"actually it is, but it\u0027s deprecated in favor of valid-interfaces the same we used in the keystone helper, I\u0027ll change it alongside the comment above which does not apply here as well","commit_id":"646724637f0942ce46a02c37480c32a807c9e7f8"},{"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":"e926588bfe40e5c53de9bf98bf23d0c17103a6f1","unresolved":false,"context_lines":[{"line_number":1,"context_line":"# Copyright (c) 2025 OpenStack Foundation"},{"line_number":2,"context_line":"#"},{"line_number":3,"context_line":"# Licensed under the Apache License, Version 2.0 (the \"License\");"},{"line_number":4,"context_line":"# you may not use this file except in compliance with the License."}],"source_content_type":"text/x-python","patch_set":4,"id":"0cfea084_553c4034","line":1,"updated":"2026-06-19 10:35:57.000000000","message":"The new placement.py config module uses \u0027Copyright (c) 2025 OpenStack Foundation\u0027 in the license header instead of the standard Apache 2.0 boilerplate used elsewhere in watcher.\n\n**Severity**: SUGGESTION | **Confidence**: 0.8\n\n**Benefit**: Consistency with the rest of the codebase and avoidance of potential licensing concerns from non-standard headers.\n\n**Recommendation**:\nUse the same Apache 2.0 license header format as the other files (e.g., the format used in watcher/conf/nova.py or watcher/conf/placement_client.py). The placement_client.py uses a slightly different variant - match whichever is most common in the conf/ directory.","commit_id":"2d9058323e4dad65c806b5b955021754baed9c85"},{"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":"e926588bfe40e5c53de9bf98bf23d0c17103a6f1","unresolved":false,"context_lines":[{"line_number":33,"context_line":"    return deprecations"},{"line_number":34,"context_line":""},{"line_number":35,"context_line":""},{"line_number":36,"context_line":"def register_opts(conf):"},{"line_number":37,"context_line":"    conf.register_group(placement)"},{"line_number":38,"context_line":"    deprecated_opts \u003d _deprecations()"},{"line_number":39,"context_line":"    ks_loading.register_adapter_conf_options("}],"source_content_type":"text/x-python","patch_set":4,"id":"72bfc10f_7eae86fe","line":36,"updated":"2026-06-19 10:35:57.000000000","message":"No placement API microversion is configured for the SDK connection. The old code explicitly set default_microversion to 1.29 via the keystoneauth Adapter. The new [placement] config group only registers keystoneauth adapter/session/auth options and does not include a microversion setting, so the SDK will use its own default which may differ from 1.29.\n\n**Severity**: HIGH | **Confidence**: 0.8\n\n**Risk**: Resource provider inventory queries may behave differently or fail if the SDK negotiates a microversion incompatible with the deployment. Features requiring microversion 1.29+ (e.g., nested resource providers, traits) may silently degrade.\n\n**Priority**: Before merge\n**Why This Matters**: Placement microversions control API behavior. The previous implementation explicitly pinned 1.29 for consistency. Dropping the microversion without verifying SDK defaults could introduce subtle behavioral regressions in production environments running older placement services.\n\n**Recommendation**:\nEither register a microversion option in the [placement] config group (matching the [nova] pattern with api_version), or verify that the OpenStackSDK placement proxy defaults to a compatible microversion and document this in the commit message.","commit_id":"2d9058323e4dad65c806b5b955021754baed9c85"}],"watcher/conf/placement_client.py":[{"author":{"_account_id":30002,"name":"Douglas Viroel","email":"viroel@gmail.com","username":"dviroel"},"change_message_id":"2b1d6b3368d53f1f70d22dac21bd1cbd56191c99","unresolved":true,"context_lines":[{"line_number":39,"context_line":"        choices\u003d[\u0027internal\u0027, \u0027public\u0027, \u0027admin\u0027],"},{"line_number":40,"context_line":"        deprecated_for_removal\u003dTrue,"},{"line_number":41,"context_line":"        deprecated_reason\u003d_("},{"line_number":42,"context_line":"            \u0027This option was replaced by the region_name \u0027"},{"line_number":43,"context_line":"            \u0027option defined by keystoneauth.\u0027"},{"line_number":44,"context_line":"        ),"},{"line_number":45,"context_line":"        deprecated_since\u003d\u00272026.2\u0027,"}],"source_content_type":"text/x-python","patch_set":1,"id":"5207c08a_bd0b63d0","line":42,"range":{"start_line":42,"start_character":45,"end_line":42,"end_character":56},"updated":"2026-06-18 18:46:15.000000000","message":"interface","commit_id":"1b42cb1522e89533b652e6fd19aec6f44519db0f"},{"author":{"_account_id":34452,"name":"Joan Gilabert","display_name":"jgilaber","email":"jgilaber@redhat.com","username":"jgilaber"},"change_message_id":"965506cdfba690570183b81e18d4a350c98d5687","unresolved":false,"context_lines":[{"line_number":39,"context_line":"        choices\u003d[\u0027internal\u0027, \u0027public\u0027, \u0027admin\u0027],"},{"line_number":40,"context_line":"        deprecated_for_removal\u003dTrue,"},{"line_number":41,"context_line":"        deprecated_reason\u003d_("},{"line_number":42,"context_line":"            \u0027This option was replaced by the region_name \u0027"},{"line_number":43,"context_line":"            \u0027option defined by keystoneauth.\u0027"},{"line_number":44,"context_line":"        ),"},{"line_number":45,"context_line":"        deprecated_since\u003d\u00272026.2\u0027,"}],"source_content_type":"text/x-python","patch_set":1,"id":"69170648_730b7237","line":42,"range":{"start_line":42,"start_character":45,"end_line":42,"end_character":56},"in_reply_to":"37abdbe8_7815c76b","updated":"2026-06-19 10:50:02.000000000","message":"Done","commit_id":"1b42cb1522e89533b652e6fd19aec6f44519db0f"},{"author":{"_account_id":34452,"name":"Joan Gilabert","display_name":"jgilaber","email":"jgilaber@redhat.com","username":"jgilaber"},"change_message_id":"5de266d40e08bd754819b140013abf253c2b9bf2","unresolved":true,"context_lines":[{"line_number":39,"context_line":"        choices\u003d[\u0027internal\u0027, \u0027public\u0027, \u0027admin\u0027],"},{"line_number":40,"context_line":"        deprecated_for_removal\u003dTrue,"},{"line_number":41,"context_line":"        deprecated_reason\u003d_("},{"line_number":42,"context_line":"            \u0027This option was replaced by the region_name \u0027"},{"line_number":43,"context_line":"            \u0027option defined by keystoneauth.\u0027"},{"line_number":44,"context_line":"        ),"},{"line_number":45,"context_line":"        deprecated_since\u003d\u00272026.2\u0027,"}],"source_content_type":"text/x-python","patch_set":1,"id":"37abdbe8_7815c76b","line":42,"range":{"start_line":42,"start_character":45,"end_line":42,"end_character":56},"in_reply_to":"5207c08a_bd0b63d0","updated":"2026-06-19 06:50:13.000000000","message":"fixed, thanks, that\u0027s what I get for writing code by hand instead of relying on an AI ;)","commit_id":"1b42cb1522e89533b652e6fd19aec6f44519db0f"},{"author":{"_account_id":30002,"name":"Douglas Viroel","email":"viroel@gmail.com","username":"dviroel"},"change_message_id":"d389401aa1e23b890208527fa774c706b650c9bc","unresolved":false,"context_lines":[{"line_number":39,"context_line":"        choices\u003d[\u0027internal\u0027, \u0027public\u0027, \u0027admin\u0027],"},{"line_number":40,"context_line":"        deprecated_for_removal\u003dTrue,"},{"line_number":41,"context_line":"        deprecated_reason\u003d_("},{"line_number":42,"context_line":"            \u0027This option was replaced by the region_name \u0027"},{"line_number":43,"context_line":"            \u0027option defined by keystoneauth.\u0027"},{"line_number":44,"context_line":"        ),"},{"line_number":45,"context_line":"        deprecated_since\u003d\u00272026.2\u0027,"}],"source_content_type":"text/x-python","patch_set":1,"id":"f0dae87c_8605f0bf","line":42,"range":{"start_line":42,"start_character":45,"end_line":42,"end_character":56},"in_reply_to":"69170648_730b7237","updated":"2026-06-19 19:17:49.000000000","message":"Lol, exactly. Proves that was you, not ai.","commit_id":"1b42cb1522e89533b652e6fd19aec6f44519db0f"},{"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":"e926588bfe40e5c53de9bf98bf23d0c17103a6f1","unresolved":false,"context_lines":[{"line_number":22,"context_line":")"},{"line_number":23,"context_line":""},{"line_number":24,"context_line":"placement_opts \u003d ["},{"line_number":25,"context_line":"    cfg.StrOpt("},{"line_number":26,"context_line":"        \u0027api_version\u0027,"},{"line_number":27,"context_line":"        default\u003d\u00271.29\u0027,"},{"line_number":28,"context_line":"        deprecated_reason\u003d_("}],"source_content_type":"text/x-python","patch_set":4,"id":"1f2b6c4d_be69ff14","line":25,"updated":"2026-06-19 10:35:57.000000000","message":"The api_version option in [placement_client] is deprecated with deprecated_reason and deprecated_since but is NOT marked with deprecated_for_removal\u003dTrue, unlike the interface and region_name options. It is also not mapped to any DeprecatedOpt in the new [placement] group.\n\n**Severity**: WARNING | **Confidence**: 0.8\n\n**Impact**: Operators who have api_version set under [placement_client] will have the setting silently ignored since the SDK connection does not use it. The inconsistency in deprecation treatment (removal vs no removal) may confuse operators reading the config reference.\n\n**Suggestion**:\nEither add deprecated_for_removal\u003dTrue to the api_version option to be consistent with the other deprecated options, or add a mapping in the _deprecations() function of placement.py if a corresponding microversion option is added to [placement].","commit_id":"2d9058323e4dad65c806b5b955021754baed9c85"}],"watcher/tests/unit/common/test_placement_helper.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":"6a99cc9e9934d9e236d2e3091176dd4c7477533e","unresolved":false,"context_lines":[{"line_number":102,"context_line":"        placement \u003d self.mock_conn.placement.resource_provider_inventories"},{"line_number":103,"context_line":"        placement.return_value \u003d list(fake_inventories.values())"},{"line_number":104,"context_line":""},{"line_number":105,"context_line":"        result \u003d self.client.get_inventories(rp_uuid)"},{"line_number":106,"context_line":""},{"line_number":107,"context_line":"        expected \u003d {"},{"line_number":108,"context_line":"            rc: placement_helper.Inventory.from_openstacksdk(inv)"}],"source_content_type":"text/x-python","patch_set":5,"id":"1b6be09b_43eefb42","line":105,"updated":"2026-06-23 11:46:11.000000000","message":"test_get_inventories_OK does not assert that resource_provider_inventories() was called with the correct rp_uuid argument. The old tests verified the request URL; the new test only checks the return value, leaving the call-argument contract untested.\n\n**Severity**: SUGGESTION | **Confidence**: 0.9\n\n**Benefit**: Adding assert_called_once_with(rp_uuid) would verify the SDK method receives the correct resource provider UUID, catching regressions if argument passing changes.\n\n**Recommendation**:\nAfter the result assertion, add: self.mock_conn.placement.resource_provider_inventories.assert_called_once_with(rp_uuid)","commit_id":"5d4682dc9de284af28879fd7ecd5d3b33b691286"}],"watcher/tests/unit/common/utils.py":[{"author":{"_account_id":30002,"name":"Douglas Viroel","email":"viroel@gmail.com","username":"dviroel"},"change_message_id":"2b1d6b3368d53f1f70d22dac21bd1cbd56191c99","unresolved":true,"context_lines":[{"line_number":151,"context_line":""},{"line_number":152,"context_line":""},{"line_number":153,"context_line":"class PlacementResourcesMixin:"},{"line_number":154,"context_line":"    def create_inventory(self, **kwargs):"},{"line_number":155,"context_line":"        \"\"\"Create an Inventory dataclass instance."},{"line_number":156,"context_line":""},{"line_number":157,"context_line":"        :param kwargs: inventory attributes"}],"source_content_type":"text/x-python","patch_set":1,"id":"b9ad2652_4255f39c","line":154,"range":{"start_line":154,"start_character":8,"end_line":154,"end_character":24},"updated":"2026-06-18 18:46:15.000000000","message":"following the pattern from previous methods it should be: create_openstacksdk_inventory","commit_id":"1b42cb1522e89533b652e6fd19aec6f44519db0f"},{"author":{"_account_id":34452,"name":"Joan Gilabert","display_name":"jgilaber","email":"jgilaber@redhat.com","username":"jgilaber"},"change_message_id":"965506cdfba690570183b81e18d4a350c98d5687","unresolved":false,"context_lines":[{"line_number":151,"context_line":""},{"line_number":152,"context_line":""},{"line_number":153,"context_line":"class PlacementResourcesMixin:"},{"line_number":154,"context_line":"    def create_inventory(self, **kwargs):"},{"line_number":155,"context_line":"        \"\"\"Create an Inventory dataclass instance."},{"line_number":156,"context_line":""},{"line_number":157,"context_line":"        :param kwargs: inventory attributes"}],"source_content_type":"text/x-python","patch_set":1,"id":"918da992_110acf8e","line":154,"range":{"start_line":154,"start_character":8,"end_line":154,"end_character":24},"in_reply_to":"3bc7a90e_7b34e312","updated":"2026-06-19 10:50:02.000000000","message":"Done","commit_id":"1b42cb1522e89533b652e6fd19aec6f44519db0f"},{"author":{"_account_id":34452,"name":"Joan Gilabert","display_name":"jgilaber","email":"jgilaber@redhat.com","username":"jgilaber"},"change_message_id":"5de266d40e08bd754819b140013abf253c2b9bf2","unresolved":true,"context_lines":[{"line_number":151,"context_line":""},{"line_number":152,"context_line":""},{"line_number":153,"context_line":"class PlacementResourcesMixin:"},{"line_number":154,"context_line":"    def create_inventory(self, **kwargs):"},{"line_number":155,"context_line":"        \"\"\"Create an Inventory dataclass instance."},{"line_number":156,"context_line":""},{"line_number":157,"context_line":"        :param kwargs: inventory attributes"}],"source_content_type":"text/x-python","patch_set":1,"id":"3bc7a90e_7b34e312","line":154,"range":{"start_line":154,"start_character":8,"end_line":154,"end_character":24},"in_reply_to":"b9ad2652_4255f39c","updated":"2026-06-19 06:50:13.000000000","message":"good point, done","commit_id":"1b42cb1522e89533b652e6fd19aec6f44519db0f"},{"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":"694d7cb54669e60b39979afa426024c9a8d594c4","unresolved":false,"context_lines":[{"line_number":158,"context_line":"        :returns: resource_provider_inventory.ResourceProviderInventory"},{"line_number":159,"context_line":"        \"\"\""},{"line_number":160,"context_line":"        inventory_info \u003d {"},{"line_number":161,"context_line":"            \"resource_class\": kwargs.pop(\u0027resource_class\u0027, \u0027VCPU\u0027),"},{"line_number":162,"context_line":"            \"total\": kwargs.pop(\u0027total\u0027, 0),"},{"line_number":163,"context_line":"            \"reserved\": kwargs.pop(\u0027reserved\u0027, 0),"},{"line_number":164,"context_line":"            \"min_unit\": kwargs.pop(\u0027min_unit\u0027, 1),"}],"source_content_type":"text/x-python","patch_set":5,"id":"0ab005db_e1d33e0e","line":161,"updated":"2026-06-19 11:12:49.000000000","message":"The PlacementResourcesMixin.create_openstacksdk_inventory defaults resource_class to VCPU which may surprise callers who forget to specify it. Consider requiring it as a positional argument or using None as default\n\n**Severity**: SUGGESTION | **Confidence**: 0.7\n\n**Benefit**: Prevents test bugs where inventory objects for non-VCPU resources accidentally get the wrong resource_class value, which would not match the expected key in get_inventories results\n\n**Recommendation**:\nChange the default from \u0027VCPU\u0027 to None or make resource_class the first positional parameter to force callers to be explicit","commit_id":"5d4682dc9de284af28879fd7ecd5d3b33b691286"}],"watcher/tests/unit/decision_engine/cluster/test_nova_cdmc.py":[{"author":{"_account_id":30002,"name":"Douglas Viroel","email":"viroel@gmail.com","username":"dviroel"},"change_message_id":"2b1d6b3368d53f1f70d22dac21bd1cbd56191c99","unresolved":true,"context_lines":[{"line_number":82,"context_line":"            ),"},{"line_number":83,"context_line":"            orc.DISK_GB: placement_helper.Inventory.from_openstacksdk("},{"line_number":84,"context_line":"                self.create_inventory("},{"line_number":85,"context_line":"                    resource_class\u003dorc.MEMORY_MB, total\u003d142, max_unit\u003d142"},{"line_number":86,"context_line":"                )"},{"line_number":87,"context_line":"            ),"},{"line_number":88,"context_line":"        }"}],"source_content_type":"text/x-python","patch_set":1,"id":"e3df89c1_2e5424f2","line":85,"range":{"start_line":85,"start_character":39,"end_line":85,"end_character":48},"updated":"2026-06-18 18:46:15.000000000","message":"DISK_GB?","commit_id":"1b42cb1522e89533b652e6fd19aec6f44519db0f"},{"author":{"_account_id":34452,"name":"Joan Gilabert","display_name":"jgilaber","email":"jgilaber@redhat.com","username":"jgilaber"},"change_message_id":"965506cdfba690570183b81e18d4a350c98d5687","unresolved":false,"context_lines":[{"line_number":82,"context_line":"            ),"},{"line_number":83,"context_line":"            orc.DISK_GB: placement_helper.Inventory.from_openstacksdk("},{"line_number":84,"context_line":"                self.create_inventory("},{"line_number":85,"context_line":"                    resource_class\u003dorc.MEMORY_MB, total\u003d142, max_unit\u003d142"},{"line_number":86,"context_line":"                )"},{"line_number":87,"context_line":"            ),"},{"line_number":88,"context_line":"        }"}],"source_content_type":"text/x-python","patch_set":1,"id":"c845d48e_280148cc","line":85,"range":{"start_line":85,"start_character":39,"end_line":85,"end_character":48},"in_reply_to":"deffeec1_f7d8ec91","updated":"2026-06-19 10:50:02.000000000","message":"Done","commit_id":"1b42cb1522e89533b652e6fd19aec6f44519db0f"},{"author":{"_account_id":34452,"name":"Joan Gilabert","display_name":"jgilaber","email":"jgilaber@redhat.com","username":"jgilaber"},"change_message_id":"5de266d40e08bd754819b140013abf253c2b9bf2","unresolved":true,"context_lines":[{"line_number":82,"context_line":"            ),"},{"line_number":83,"context_line":"            orc.DISK_GB: placement_helper.Inventory.from_openstacksdk("},{"line_number":84,"context_line":"                self.create_inventory("},{"line_number":85,"context_line":"                    resource_class\u003dorc.MEMORY_MB, total\u003d142, max_unit\u003d142"},{"line_number":86,"context_line":"                )"},{"line_number":87,"context_line":"            ),"},{"line_number":88,"context_line":"        }"}],"source_content_type":"text/x-python","patch_set":1,"id":"deffeec1_f7d8ec91","line":85,"range":{"start_line":85,"start_character":39,"end_line":85,"end_character":48},"in_reply_to":"e3df89c1_2e5424f2","updated":"2026-06-19 06:50:13.000000000","message":"indeed, that is another copy-paste error","commit_id":"1b42cb1522e89533b652e6fd19aec6f44519db0f"}]}
