)]}'
{"/PATCHSET_LEVEL":[{"author":{"_account_id":34452,"name":"Joan Gilabert","display_name":"jgilaber","email":"jgilaber@redhat.com","username":"jgilaber"},"change_message_id":"564c346592409f58eb8a2d594a192d2843360f92","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":1,"id":"ab182aaa_5ec543c2","updated":"2026-07-31 10:19:06.000000000","message":"this is WIP and will need to be updated","commit_id":"d8992a5f918b02d03067a85a3fe92dc8c9ed1aa3"}],"watcher/tests/functional/base.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":"763a9f4d64fb3a9906836431e74de04293024a61","unresolved":false,"context_lines":[{"line_number":282,"context_line":"                start_de\u003dself.START_DECISION_ENGINE,"},{"line_number":283,"context_line":"                start_applier\u003dself.START_APPLIER,"},{"line_number":284,"context_line":"                log_name\u003dself.id(),"},{"line_number":285,"context_line":"                cast_as_call\u003dself.CAST_AS_CALL,"},{"line_number":286,"context_line":"                compute_topology\u003dself.COMPUTE_TOPOLOGY,"},{"line_number":287,"context_line":"                use_ironic_emulator\u003dself.USE_IRONIC_EMULATOR,"},{"line_number":288,"context_line":"            )"}],"source_content_type":"text/x-python","patch_set":2,"id":"669fec4d_49f77994","line":285,"updated":"2026-07-31 10:53:07.000000000","message":"The WatcherFunctionalTestCase defines IRONIC_NODES \u003d None alongside USE_IRONIC_EMULATOR, but setUp() only passes use_ironic_emulator to WatcherEnvironment and omits ironic_nodes\u003dself.IRONIC_NODES. Setting IRONIC_NODES on a subclass has no effect.\n\n**Severity**: SUGGESTION | **Confidence**: 0.9\n\n**Benefit**: A test author setting IRONIC_NODES on a subclass would expect initial Ironic topology to be loaded, but nothing would happen. They would need to discover that load_topology(ironic_nodes\u003d...) is the only working path, wasting time and potentially masking test failures.\n\n**Recommendation**:\nEither pass `ironic_nodes\u003dself.IRONIC_NODES` in the WatcherEnvironment constructor call within setUp(), or remove the IRONIC_NODES class attribute if load_topology() is intended as the sole mechanism for loading Ironic nodes.","commit_id":"0d816d655cedf8052cc50e292cde079446e6cdb0"}],"watcher/tests/functional/ironic_topology.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":"c9bd30f98825850a2f6bc1fa6555d323518c4612","unresolved":false,"context_lines":[{"line_number":120,"context_line":"    return \u0027cccc%04d-0000-0000-0000-%012d\u0027 % (index, index)"},{"line_number":121,"context_line":""},{"line_number":122,"context_line":""},{"line_number":123,"context_line":"def _compute_node_uuid(index):"},{"line_number":124,"context_line":"    \"\"\"Deterministic UUID for the linked compute node at *index*."},{"line_number":125,"context_line":""},{"line_number":126,"context_line":"    Must match ``topology._node_uuid`` so ironic nodes auto-link to"}],"source_content_type":"text/x-python","patch_set":3,"id":"77824502_9e2eb809","line":123,"updated":"2026-09-16 17:01:12.000000000","message":"The new ironic_topology module re-implements helpers that already exist in the sibling compute topology module: _asdict_strip_none is copied verbatim (identical body and docstring) and _compute_node_uuid re-implements the exact compute-node UUID format produced by topology._node_uuid, keeping the two in sync only through a docstring comment. Both the None-stripping semantics and the ironic-to-compute UUID linking invariant now have two independent implementations that can be edited separately and drift apart.\n\n**Severity**: SUGGESTION | **Confidence**: 0.86\n\n**Impact**: If the compute UUID scheme or the None-stripping rule is later changed in topology.py without mirroring the edit here, ironic nodes silently link to compute_node_id values that match no compute node; metal_helper.list_compute_nodes then logs \u0027Cannot find hypervisor\u0027 and skips every baremetal node, so strategies see an empty node pool. Test assertions would catch wholesale breakage, but partially-diverged edits produce confusing failures or reduced test coverage rather than an obvious cause.\n\n**Recommendation**:\nImport the shared pieces from the sibling module instead of copying: use topology._node_uuid(global_idx) to default compute_node_id in IronicTopology.add_nodes, and either reuse topology.normalize-style helpers or move _asdict_strip_none into one shared location so each invariant has a single implementation.","commit_id":"b7534e55ad5e851fdb256ac0feab58a632592ed0"},{"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":"6f5e582e9b2f2c95059cb637ee97bfc35353a825","unresolved":false,"context_lines":[{"line_number":120,"context_line":"    return \u0027cccc%04d-0000-0000-0000-%012d\u0027 % (index, index)"},{"line_number":121,"context_line":""},{"line_number":122,"context_line":""},{"line_number":123,"context_line":"def _compute_node_uuid(index):"},{"line_number":124,"context_line":"    \"\"\"Deterministic UUID for the linked compute node at *index*."},{"line_number":125,"context_line":""},{"line_number":126,"context_line":"    Must match ``topology._node_uuid`` so ironic nodes auto-link to"}],"source_content_type":"text/x-python","patch_set":6,"id":"de2bb886_a8e2440a","line":123,"updated":"2026-09-18 12:18:27.000000000","message":"The new watcher/tests/functional/ironic_topology.py defines _compute_node_uuid() as a second, independent implementation of the compute node UUID scheme that functional/topology.py already owns as _node_uuid(). Both hard-code the format \u0027aaaa%04d-0000-0000-0000-%012d\u0027, and the coupling is documented only in comments: the new helper\u0027s docstring says \u0027Must match ``topology._node_uuid``\u0027. This scheme is the invariant that auto-links every ironic node to its hypervisor (add_nodes() sets compute_node_id from _compute_node_uuid), and metal_helper/ironic.list_compute_nodes() later matches that value against nova hypervisor ids. If either copy is edited without the other, ironic nodes silently point at nonexistent hypervisors.\n\n**Severity**: SUGGESTION | **Confidence**: 0.85\n\n**Impact**: The ironic-node-to-compute-node linking that every saving_energy functional test depends on now has two independently editable implementations. A future change to either copy would not fail at the duplication site: nodes would be skipped with \u0027Cannot find hypervisor\u0027 warnings and the strategy would see a smaller cluster, so tests fail indirectly with confusing scenario sizes instead of pointing at the out-of-sync constant.\n\n**Recommendation**:\nDelete _compute_node_uuid and reuse the existing helper: import the topology module in ironic_topology.py (e.g. \u0027from watcher.tests.functional import topology as topo_mod\u0027) and call topo_mod._node_uuid(global_idx) in add_nodes(); or move the shared deterministic UUID helpers into a single module that both topology modules import.","commit_id":"f49c3ca2436e7199cd2767612eac677c128fb34c"}],"watcher/tests/local_fixtures/ironic.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":"c9bd30f98825850a2f6bc1fa6555d323518c4612","unresolved":false,"context_lines":[{"line_number":42,"context_line":"    Installs wsgi-intercept for the Ironic emulator and patches"},{"line_number":43,"context_line":"    ``OpenStackClients.ironic`` so that all callers (IronicHelper,"},{"line_number":44,"context_line":"    metal_helper.ironic, etc.) get a real ``ironicclient`` routed"},{"line_number":45,"context_line":"    to the in-process Flask app."},{"line_number":46,"context_line":""},{"line_number":47,"context_line":"    :param ironic_topology: An ``IronicTopology`` instance."},{"line_number":48,"context_line":"    \"\"\""}],"source_content_type":"text/x-python","patch_set":3,"id":"763fc8d3_3e4b21e2","line":45,"updated":"2026-09-16 17:01:12.000000000","message":"The class docstring of the new IronicFixture claims callers get a real ironicclient routed \"to the in-process Flask app\", but the emulated application is a Pecan WSGI app: it is built with pecan.make_app in the shared base emulator and wrapped in a small version-header WSGI middleware. Nothing in the test stack uses Flask.\n\n**Severity**: SUGGESTION | **Confidence**: 0.92\n\n**Impact**: A maintainer debugging interceptor or routing behavior may look for Flask-specific machinery (request context, blueprints) that does not exist, and the wrong framework name undermines confidence in otherwise accurate fixture documentation.\n\n**Recommendation**:\nReplace \"Flask app\" with \"Pecan WSGI app\" so the docstring matches IronicAPIEmulator and the Nova/Placement fixtures\u0027 description of the same pattern.","commit_id":"b7534e55ad5e851fdb256ac0feab58a632592ed0"}]}
