)]}'
{"/PATCHSET_LEVEL":[{"author":{"_account_id":30002,"name":"Douglas Viroel","email":"viroel@gmail.com","username":"dviroel"},"change_message_id":"38c364c787b95b9f0803c5e5374acb7bed4f1b1b","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":6,"id":"458bb991_f4696f4c","updated":"2026-10-23 15:41:05.000000000","message":"This in general looks good. Some comments inline, most of them suggestions. But this is very likely candidate to merge. Thanks!","commit_id":"30a9c12b8cf7e56b3112e50da4bcede84b7c39f9"}],"doc/source/contributor/testing.rst":[{"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":"e9f073a6382d83ecc90436b83a46cf645668678e","unresolved":false,"context_lines":[{"line_number":1084,"context_line":"                \u0027parameters\u0027: {"},{"line_number":1085,"context_line":"                    \u0027metrics\u0027: [\u0027instance_cpu_usage\u0027],"},{"line_number":1086,"context_line":"                    \u0027thresholds\u0027: {\u0027instance_cpu_usage\u0027: 0.10},"},{"line_number":1087,"context_line":"                    \u0027weights\u0027: {\u0027instance_cpu_usage\u0027: 1.0},"},{"line_number":1088,"context_line":"                    \u0027host_choice\u0027: \u0027fullsearch\u0027,"},{"line_number":1089,"context_line":"                    \u0027period\u0027: 300,"},{"line_number":1090,"context_line":"                },"}],"source_content_type":"text/x-rst","patch_set":3,"id":"5d1756f1_58ddc5b5","line":1087,"updated":"2026-06-25 09:42:13.000000000","message":"Documentation \u0027Complete example\u0027 uses incorrect strategy parameter names: \u0027instance_cpu_usage\u0027 instead of \u0027instance_cpu_usage_weight\u0027, and \u0027period\u0027 instead of \u0027periods\u0027 dict.\n\n**Severity**: WARNING | **Confidence**: 0.9\n\n**Impact**: A contributor copying this example verbatim will get a failing audit or incorrect strategy behavior. The strategy expects weight keys with a \u0027_weight\u0027 suffix and a \u0027periods\u0027 dict with \u0027instance\u0027/\u0027compute_node\u0027 keys (verified against the strategy schema and the real tests in this patch).\n\n**Suggestion**:\nChange \u0027weights\u0027: {\u0027instance_cpu_usage\u0027: 1.0} to \u0027weights\u0027: {\u0027instance_cpu_usage_weight\u0027: 1.0}, and change \u0027period\u0027: 300 to \u0027periods\u0027: {\u0027instance\u0027: 720, \u0027compute_node\u0027: 600}, \u0027aggregation_method\u0027: {\u0027instance\u0027: \u0027mean\u0027, \u0027compute_node\u0027: \u0027mean\u0027}. Match the parameter structure used in the actual test methods in test_workload_stabilization.py.","commit_id":"979ce88e27d631a88790a239a1133a5b2aef1389"},{"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":"46229ec412a7dce001b50cf3ac8c20dfcc75a6e5","unresolved":false,"context_lines":[{"line_number":824,"context_line":"Host FQDNs are constructed as ``hostname + \u0027.example.com\u0027`` (configurable"},{"line_number":825,"context_line":"via the ``fqdn_suffix`` parameter on ``load_from_topology()``)."},{"line_number":826,"context_line":""},{"line_number":827,"context_line":"Distributing metrics across large topologies"},{"line_number":828,"context_line":"^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^"},{"line_number":829,"context_line":""},{"line_number":830,"context_line":"For large clusters (tens or hundreds of nodes), setting metrics"}],"source_content_type":"text/x-rst","patch_set":5,"id":"9b40dbbd_3867f8ed","line":827,"updated":"2026-10-09 08:41:34.000000000","message":"The new \u0027Distributing metrics across large topologies\u0027 section of doc/source/contributor/testing.rst presents ComputeTopology.distribute_cpu() and distribute_ram() as existing methods, with a worked example and a parameter list, but neither method is implemented in watcher/tests/functional/topology.py or anywhere else in the tree. The example also passes percentage-scale values (hosts_mean\u003d60.0, instances_mean\u003d40.0) that contradict the 0-1 fraction convention the same section defines a few paragraphs above, suggesting it was written against a different (unmerged) implementation of the helpers.\n\n**Severity**: WARNING | **Confidence**: 0.95\n\n**Impact**: Developers following the new documentation get AttributeError when building the topology, since the methods do not exist. Even after a future implementation, the percentage-scale example values would contradict the 0-1 fraction convention documented in the same section and would feed the emulator conversion (cpu * 100) with wrong units.\n\n**Suggestion**:\nEither implement distribute_cpu()/distribute_ram() on ComputeTopology in this change, or remove the \u0027Distributing metrics across large topologies\u0027 section until those methods land. When implemented, use 0-1 fraction example values consistent with the documented convention.","commit_id":"9dd0eb885df0afc7035e4f116eb8628d7883a39e"},{"author":{"_account_id":16312,"name":"Alfredo Moralejo","email":"amoralej@redhat.com","username":"amoralej"},"change_message_id":"064c9104e17e88502f3da144a9f8dc7cd8d67edd","unresolved":false,"context_lines":[{"line_number":824,"context_line":"Host FQDNs are constructed as ``hostname + \u0027.example.com\u0027`` (configurable"},{"line_number":825,"context_line":"via the ``fqdn_suffix`` parameter on ``load_from_topology()``)."},{"line_number":826,"context_line":""},{"line_number":827,"context_line":"Distributing metrics across large topologies"},{"line_number":828,"context_line":"^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^"},{"line_number":829,"context_line":""},{"line_number":830,"context_line":"For large clusters (tens or hundreds of nodes), setting metrics"}],"source_content_type":"text/x-rst","patch_set":5,"id":"6116b6fe_f84adaa2","line":827,"in_reply_to":"9b40dbbd_3867f8ed","updated":"2026-10-26 14:20:06.000000000","message":"Yep, need to update the doc.","commit_id":"9dd0eb885df0afc7035e4f116eb8628d7883a39e"},{"author":{"_account_id":30002,"name":"Douglas Viroel","email":"viroel@gmail.com","username":"dviroel"},"change_message_id":"38c364c787b95b9f0803c5e5374acb7bed4f1b1b","unresolved":true,"context_lines":[{"line_number":763,"context_line":"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"},{"line_number":764,"context_line":""},{"line_number":765,"context_line":"Strategies that rely on real-time metrics (``workload_stabilization``,"},{"line_number":766,"context_line":"``zone_migration``, etc.) need a datasource.  The Prometheus API emulator"},{"line_number":767,"context_line":"serves PromQL query responses from in-memory metric data, eliminating the"},{"line_number":768,"context_line":"need for an external Prometheus server."},{"line_number":769,"context_line":""}],"source_content_type":"text/x-rst","patch_set":6,"id":"bd9d273b_78bb5ae1","line":766,"range":{"start_line":766,"start_character":2,"end_line":766,"end_character":16},"updated":"2026-10-23 15:41:05.000000000","message":"zone_migration doesn\u0027t rely on metrics https://docs.openstack.org/watcher/latest/strategies/zone_migration.html#metrics","commit_id":"30a9c12b8cf7e56b3112e50da4bcede84b7c39f9"},{"author":{"_account_id":16312,"name":"Alfredo Moralejo","email":"amoralej@redhat.com","username":"amoralej"},"change_message_id":"064c9104e17e88502f3da144a9f8dc7cd8d67edd","unresolved":true,"context_lines":[{"line_number":763,"context_line":"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"},{"line_number":764,"context_line":""},{"line_number":765,"context_line":"Strategies that rely on real-time metrics (``workload_stabilization``,"},{"line_number":766,"context_line":"``zone_migration``, etc.) need a datasource.  The Prometheus API emulator"},{"line_number":767,"context_line":"serves PromQL query responses from in-memory metric data, eliminating the"},{"line_number":768,"context_line":"need for an external Prometheus server."},{"line_number":769,"context_line":""}],"source_content_type":"text/x-rst","patch_set":6,"id":"cd04304e_6c102ecf","line":766,"range":{"start_line":766,"start_character":2,"end_line":766,"end_character":16},"in_reply_to":"bd9d273b_78bb5ae1","updated":"2026-10-26 14:20:06.000000000","message":"right, i will update it.","commit_id":"30a9c12b8cf7e56b3112e50da4bcede84b7c39f9"}],"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":"504b596dda4368e151cc192a27d0afbbb7a4a2c2","unresolved":false,"context_lines":[{"line_number":348,"context_line":"        Requires USE_PROMETHEUS_EMULATOR \u003d True (or METRICS_HOSTS set)"},{"line_number":349,"context_line":"        on the test class so the Prometheus emulator fixture exists."},{"line_number":350,"context_line":"        \"\"\""},{"line_number":351,"context_line":"        self.env.prometheus_fixture.reload_metrics("},{"line_number":352,"context_line":"            hosts\u003dhosts, instances\u003dinstances"},{"line_number":353,"context_line":"        )"},{"line_number":354,"context_line":""}],"source_content_type":"text/x-python","patch_set":4,"id":"e4101ccb_04831610","line":351,"updated":"2026-07-02 19:50:17.000000000","message":"load_metrics() accesses self.env.prometheus_fixture without a guard; when USE_PROMETHEUS_EMULATOR is False the attribute is None and reload_metrics raises an opaque AttributeError instead of a clear error.\n\n**Severity**: HIGH | **Confidence**: 0.8\n\n**Risk**: A test that calls self.load_metrics() without setting USE_PROMETHEUS_EMULATOR\u003dTrue fails with \u0027NoneType object has no attribute reload_metrics\u0027, which gives no hint about the missing flag, wasting debugging time.\n\n**Priority**: Before merge\n**Why This Matters**: The docstring says the method \u0027Requires USE_PROMETHEUS_EMULATOR \u003d True\u0027 but the code does not enforce or check this precondition, so the contract is unguarded and the failure mode is hostile to test authors.\n\n**Recommendation**:\nAdd an explicit guard at the top of load_metrics, e.g.: if self.env.prometheus_fixture is None: raise RuntimeError(\u0027load_metrics() requires USE_PROMETHEUS_EMULATOR \u003d True on the test class\u0027). This turns a confusing AttributeError into an actionable message.","commit_id":"8b7938f71a7b660b6cc8f1b3d15da62591faed9d"}],"watcher/tests/functional/test_workload_stabilization.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":"e9f073a6382d83ecc90436b83a46cf645668678e","unresolved":false,"context_lines":[{"line_number":1035,"context_line":"                params \u003d dict(base_params)"},{"line_number":1036,"context_line":"                params[\u0027thresholds\u0027] \u003d {\u0027instance_cpu_usage\u0027: threshold}"},{"line_number":1037,"context_line":""},{"line_number":1038,"context_line":"                resp \u003d self.admin_api.post("},{"line_number":1039,"context_line":"                    \u0027/audits\u0027,"},{"line_number":1040,"context_line":"                    {"},{"line_number":1041,"context_line":"                        \u0027audit_type\u0027: \u0027ONESHOT\u0027,"}],"source_content_type":"text/x-python","patch_set":3,"id":"b3ae98f0_d5fcb92b","line":1038,"updated":"2026-06-25 09:42:13.000000000","message":"The audit-creation, action-fetching, and assertion logic is duplicated across test_threshold_impact_on_migrations (lines 1038-1132), test_workload_stabilization_with_both_metrics (lines 1242-1339), and test_workload_stabilization_weight_impact (lines 1385-1479).\n\n**Severity**: SUGGESTION | **Confidence**: 0.9\n\n**Benefit**: Extracting a shared helper (e.g. _run_parametrized_audit) for the common create-audit, wait, fetch-actions, assert-migrations, assert-indicators flow would reduce ~300 lines of near-identical code and make future parametrized tests easier to add and maintain.\n\n**Recommendation**:\nAdd a private helper that accepts (params, topology, metrics, expected_ap_state, expected_migrations, sd_before, sd_after, instances_count) and encapsulates the repeated post-wait-assert cycle. The existing _create_audit_and_get_actions helper covers part of this but not the efficacy-indicator assertions.","commit_id":"979ce88e27d631a88790a239a1133a5b2aef1389"},{"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":"e9f073a6382d83ecc90436b83a46cf645668678e","unresolved":false,"context_lines":[{"line_number":1135,"context_line":"        \"\"\"Balanced cluster produces no migrations."},{"line_number":1136,"context_line":""},{"line_number":1137,"context_line":"        Both hosts have similar CPU (~30%), so standard deviation"},{"line_number":1138,"context_line":"        is below the threshold. No migrations should be proposed."},{"line_number":1139,"context_line":"        \"\"\""},{"line_number":1140,"context_line":"        actions \u003d self._create_audit_no_actions("},{"line_number":1141,"context_line":"            parameters\u003d{"}],"source_content_type":"text/x-python","patch_set":3,"id":"5b8a14e4_552e9cb6","line":1138,"updated":"2026-06-25 09:42:13.000000000","message":"Test docstring states hosts have ~30% CPU but the actual BALANCED_HOSTS metrics define compute-1 at 22% and compute-2 at 20%.\n\n**Severity**: WARNING | **Confidence**: 0.9\n\n**Impact**: Minor: the docstring misleads a reader trying to understand or debug the test. The comment block above BALANCED_HOSTS (line 170-174) correctly documents 22%/20%, so the in-method docstring is inconsistent with the data it references.\n\n**Suggestion**:\nUpdate the docstring to say \u0027Both hosts have similar CPU (~20-22%)\u0027 to match the actual BALANCED_HOSTS metric values.","commit_id":"979ce88e27d631a88790a239a1133a5b2aef1389"},{"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":"504b596dda4368e151cc192a27d0afbbb7a4a2c2","unresolved":false,"context_lines":[{"line_number":1053,"context_line":""},{"line_number":1054,"context_line":"                self._wait_for_audit_state(audit_uuid, \u0027SUCCEEDED\u0027)"},{"line_number":1055,"context_line":""},{"line_number":1056,"context_line":"                resp \u003d self.admin_api.get("},{"line_number":1057,"context_line":"                    \u0027/action_plans?audit_uuid\u003d%s\u0027 % audit_uuid"},{"line_number":1058,"context_line":"                )"},{"line_number":1059,"context_line":"                action_plans \u003d resp.json()[\u0027action_plans\u0027]"}],"source_content_type":"text/x-python","patch_set":4,"id":"c5c52f1a_1b98c7b4","line":1056,"updated":"2026-07-02 19:50:17.000000000","message":"test_workload_stabilization.py duplicates the audit/action-fetch/efficacy-assertion sequence nearly verbatim across test_threshold_impact_on_migrations, _with_both_metrics, _weight_impact, and the three aggregate_scope subTests (13 admin_api.post sites, 5 copies of the migrate_actions loop).\n\n**Severity**: WARNING | **Confidence**: 0.9\n\n**Impact**: Duplicated assertion logic means a change to how actions are fetched or validated must be applied in many places; copy-paste drift will cause some copies to diverge and mask bugs. The file is 1787 lines where a handful of shared helpers could cut it substantially.\n\n**Suggestion**:\nExtract a shared helper such as _run_audit_and_collect_migrations(parameters, topology, metrics, scope) returning (migrate_actions, action_plan, indicators), and a _assert_migrations(migrate_actions, expected) helper. The existing _create_audit_and_get_actions already does part of this but the parametrized tests bypass it and re-implement the flow inline.","commit_id":"8b7938f71a7b660b6cc8f1b3d15da62591faed9d"},{"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":"46229ec412a7dce001b50cf3ac8c20dfcc75a6e5","unresolved":false,"context_lines":[{"line_number":435,"context_line":"        4 compute nodes, 10 VMs (4 vcpus each).  Host CPU"},{"line_number":436,"context_line":"        [85%, 50%, 20%, 10%], SD ~ 0.29.  Three threshold levels:"},{"line_number":437,"context_line":""},{"line_number":438,"context_line":"        - threshold 0.10 -\u003e 4 migrations (stops when SD \u003c 0.10)"},{"line_number":439,"context_line":"        - threshold 0.25 -\u003e 1 migration  (stops when SD \u003c 0.25)"},{"line_number":440,"context_line":"        - threshold 0.30 -\u003e 0 migrations (SD \u003c threshold, no action)"},{"line_number":441,"context_line":""}],"source_content_type":"text/x-python","patch_set":5,"id":"d9469081_9bb4ac3a","line":438,"updated":"2026-10-09 08:41:34.000000000","message":"Three docstrings in the new test module summarise expected outcomes that the assertions below them refute: (1) test_threshold_impact_on_migrations says \u0027threshold 0.10 -\u003e 4 migrations\u0027 while the case data and assertions expect 2; (2) test_workload_stabilization_with_both_metrics says \u0027cpu\u003d0.10 ram\u003d0.10 -\u003e 3 migrations\u0027 while expecting 2; (3) test_workload_stabilization_aggregate_scope says \u0027agg-high scope -\u003e 1 migration (vm-5 c1-\u003ec2, SD drops to 0.045)\u0027 and \u0027both + exclude c1 -\u003e ... SD 0.057\u0027 while the assertions expect vm-3 (c1-\u003ec2) with sd_after 0.005 and vm-7 with sd_after 0.054. The enforced expectations (and the per-case inline comments) are the correct, self-consistent values.\n\n**Severity**: SUGGESTION | **Confidence**: 0.92\n\n**Impact**: Maintainers reading the docstrings to understand a scenario or to update the tests after a strategy change would start from wrong expected values and may \u0027fix\u0027 assertions toward the docstring numbers. The duplication between docstring summaries and case data creates two independently editable copies of the same expectation that already disagree.\n\n**Recommendation**:\nCorrect the docstring bullets to match the enforced expectations (2 migrations at threshold 0.10; 2 migrations at cpu\u003dram\u003d0.10; vm-3 c1-\u003ec2 with sd_after 0.005; vm-7 c2-\u003ec4 with sd_after 0.054), or drop the duplicated expected-value summaries from the docstrings and rely on the per-case comments next to the case data.","commit_id":"9dd0eb885df0afc7035e4f116eb8628d7883a39e"},{"author":{"_account_id":16312,"name":"Alfredo Moralejo","email":"amoralej@redhat.com","username":"amoralej"},"change_message_id":"064c9104e17e88502f3da144a9f8dc7cd8d67edd","unresolved":false,"context_lines":[{"line_number":435,"context_line":"        4 compute nodes, 10 VMs (4 vcpus each).  Host CPU"},{"line_number":436,"context_line":"        [85%, 50%, 20%, 10%], SD ~ 0.29.  Three threshold levels:"},{"line_number":437,"context_line":""},{"line_number":438,"context_line":"        - threshold 0.10 -\u003e 4 migrations (stops when SD \u003c 0.10)"},{"line_number":439,"context_line":"        - threshold 0.25 -\u003e 1 migration  (stops when SD \u003c 0.25)"},{"line_number":440,"context_line":"        - threshold 0.30 -\u003e 0 migrations (SD \u003c threshold, no action)"},{"line_number":441,"context_line":""}],"source_content_type":"text/x-python","patch_set":5,"id":"12652d07_4dc78b42","line":438,"in_reply_to":"d9469081_9bb4ac3a","updated":"2026-10-26 14:20:06.000000000","message":"Will update in next PS when i get more feedback from contributors.","commit_id":"9dd0eb885df0afc7035e4f116eb8628d7883a39e"},{"author":{"_account_id":30002,"name":"Douglas Viroel","email":"viroel@gmail.com","username":"dviroel"},"change_message_id":"38c364c787b95b9f0803c5e5374acb7bed4f1b1b","unresolved":true,"context_lines":[{"line_number":120,"context_line":"# Host RAM: [0.50, 0.30, 0.10, 0.10]."},{"line_number":121,"context_line":"#"},{"line_number":122,"context_line":"# Instance values are physically consistent with host values."},{"line_number":123,"context_line":"# Uses host_choice\u003d\u0027cycle\u0027 to avoid the fullsearch duplicate bug"},{"line_number":124,"context_line":"# with 3+ nodes."},{"line_number":125,"context_line":""},{"line_number":126,"context_line":"FOUR_NODE_TOPOLOGY \u003d ("},{"line_number":127,"context_line":"    topology.ComputeTopology()"}],"source_content_type":"text/x-python","patch_set":6,"id":"a5dc78a2_402fb5fb","line":124,"range":{"start_line":123,"start_character":0,"end_line":124,"end_character":16},"updated":"2026-10-23 15:41:05.000000000","message":"please file a bug if doesnt exist yet, we could link it here for future.","commit_id":"30a9c12b8cf7e56b3112e50da4bcede84b7c39f9"},{"author":{"_account_id":16312,"name":"Alfredo Moralejo","email":"amoralej@redhat.com","username":"amoralej"},"change_message_id":"064c9104e17e88502f3da144a9f8dc7cd8d67edd","unresolved":true,"context_lines":[{"line_number":120,"context_line":"# Host RAM: [0.50, 0.30, 0.10, 0.10]."},{"line_number":121,"context_line":"#"},{"line_number":122,"context_line":"# Instance values are physically consistent with host values."},{"line_number":123,"context_line":"# Uses host_choice\u003d\u0027cycle\u0027 to avoid the fullsearch duplicate bug"},{"line_number":124,"context_line":"# with 3+ nodes."},{"line_number":125,"context_line":""},{"line_number":126,"context_line":"FOUR_NODE_TOPOLOGY \u003d ("},{"line_number":127,"context_line":"    topology.ComputeTopology()"}],"source_content_type":"text/x-python","patch_set":6,"id":"9060c7de_87c3784f","line":124,"range":{"start_line":123,"start_character":0,"end_line":124,"end_character":16},"in_reply_to":"a5dc78a2_402fb5fb","updated":"2026-10-26 14:20:06.000000000","message":"it\u0027s https://bugs.launchpad.net/watcher/+bug/2170351","commit_id":"30a9c12b8cf7e56b3112e50da4bcede84b7c39f9"},{"author":{"_account_id":30002,"name":"Douglas Viroel","email":"viroel@gmail.com","username":"dviroel"},"change_message_id":"38c364c787b95b9f0803c5e5374acb7bed4f1b1b","unresolved":true,"context_lines":[{"line_number":1027,"context_line":"                )"},{"line_number":1028,"context_line":"                self.assertEqual(9.0, indicators[\u0027instances_count\u0027])"},{"line_number":1029,"context_line":""},{"line_number":1030,"context_line":"    def test_workload_stabilization_aggregate_scope(self):"},{"line_number":1031,"context_line":"        \"\"\"Aggregate scope limits which nodes the strategy sees."},{"line_number":1032,"context_line":""},{"line_number":1033,"context_line":"        Same 4-node cluster split into two aggregates:"}],"source_content_type":"text/x-python","patch_set":6,"id":"3dfa0b22_9733d89a","line":1030,"range":{"start_line":1030,"start_character":0,"end_line":1030,"end_character":58},"updated":"2026-10-23 15:41:05.000000000","message":"Mixed feelings about these tests with scope. You could build different topologies without using scope, and have scope related tests in another place. All strategies should see the  scoped compute model when using the audit scope and we don\u0027t need to validate that in all of them. So we need to discuss about having tests for scope in another place I think. I would not block because of this because we don\u0027t have the proper scope tests somewhere, but something to discuss.","commit_id":"30a9c12b8cf7e56b3112e50da4bcede84b7c39f9"},{"author":{"_account_id":16312,"name":"Alfredo Moralejo","email":"amoralej@redhat.com","username":"amoralej"},"change_message_id":"064c9104e17e88502f3da144a9f8dc7cd8d67edd","unresolved":true,"context_lines":[{"line_number":1027,"context_line":"                )"},{"line_number":1028,"context_line":"                self.assertEqual(9.0, indicators[\u0027instances_count\u0027])"},{"line_number":1029,"context_line":""},{"line_number":1030,"context_line":"    def test_workload_stabilization_aggregate_scope(self):"},{"line_number":1031,"context_line":"        \"\"\"Aggregate scope limits which nodes the strategy sees."},{"line_number":1032,"context_line":""},{"line_number":1033,"context_line":"        Same 4-node cluster split into two aggregates:"}],"source_content_type":"text/x-python","patch_set":6,"id":"1ee11de4_23b26eea","line":1030,"range":{"start_line":1030,"start_character":0,"end_line":1030,"end_character":58},"in_reply_to":"3dfa0b22_9733d89a","updated":"2026-10-26 14:20:06.000000000","message":"I think it makes sense to have scope tests which are \"strategy-agnostic\" by just checking the content on the model but i think there is also value in testing the end to end in functional tests too given the low cost in time and resources and the fact that testing end-to-end may uncover issues in the integration between strategies and model. Currently, the critical point is about excuding instances while keeping the hosts but in future there may be other cases so keeping the end-to-end tests cover any potential case in future.","commit_id":"30a9c12b8cf7e56b3112e50da4bcede84b7c39f9"},{"author":{"_account_id":30002,"name":"Douglas Viroel","email":"viroel@gmail.com","username":"dviroel"},"change_message_id":"38c364c787b95b9f0803c5e5374acb7bed4f1b1b","unresolved":true,"context_lines":[{"line_number":1269,"context_line":"            )"},{"line_number":1270,"context_line":"            self.assertEqual(5.0, indicators[\u0027instances_count\u0027])"},{"line_number":1271,"context_line":""},{"line_number":1272,"context_line":"    def test_workload_stabilization_excluded_instance(self):"},{"line_number":1273,"context_line":"        \"\"\"Excluded instance is not migrated even from overloaded host."},{"line_number":1274,"context_line":""},{"line_number":1275,"context_line":"        Scope excludes vm-4 (the highest CPU instance on compute-1"}],"source_content_type":"text/x-python","patch_set":6,"id":"3bb44a11_6b734a80","line":1272,"range":{"start_line":1272,"start_character":8,"end_line":1272,"end_character":53},"updated":"2026-10-23 15:41:05.000000000","message":"This makes sense to be here since excluding instances is part of the strategy code today. But something that we should be fixing in the future too.","commit_id":"30a9c12b8cf7e56b3112e50da4bcede84b7c39f9"},{"author":{"_account_id":30002,"name":"Douglas Viroel","email":"viroel@gmail.com","username":"dviroel"},"change_message_id":"38c364c787b95b9f0803c5e5374acb7bed4f1b1b","unresolved":true,"context_lines":[{"line_number":1470,"context_line":"            self.assertEqual(\u0027compute-2\u0027, params[\u0027destination_node\u0027])"},{"line_number":1471,"context_line":"            self.assertEqual(\u0027live\u0027, params[\u0027migration_type\u0027])"},{"line_number":1472,"context_line":""},{"line_number":1473,"context_line":"    def test_workload_stabilization_availability_zone_scope(self):"},{"line_number":1474,"context_line":"        \"\"\"availability_zones scope limits the nodes the strategy sees."},{"line_number":1475,"context_line":""},{"line_number":1476,"context_line":"        FOUR_NODE_AZ has the same layout as FOUR_NODE_TOPOLOGY but"}],"source_content_type":"text/x-python","patch_set":6,"id":"1072bc62_aca0b125","line":1473,"range":{"start_line":1473,"start_character":8,"end_line":1473,"end_character":59},"updated":"2026-10-23 15:41:05.000000000","message":"same comment as before.","commit_id":"30a9c12b8cf7e56b3112e50da4bcede84b7c39f9"}],"watcher/tests/functional/topology.py":[{"author":{"_account_id":30002,"name":"Douglas Viroel","email":"viroel@gmail.com","username":"dviroel"},"change_message_id":"38c364c787b95b9f0803c5e5374acb7bed4f1b1b","unresolved":true,"context_lines":[{"line_number":181,"context_line":"                vm_index +\u003d 1"},{"line_number":182,"context_line":"        return self"},{"line_number":183,"context_line":""},{"line_number":184,"context_line":"    def update_compute(self, hostname, **kwargs):"},{"line_number":185,"context_line":"        \"\"\"Update fields on the ComputeNode with the given *hostname*."},{"line_number":186,"context_line":""},{"line_number":187,"context_line":"        A ``metrics`` kwarg is merged into the node\u0027s existing"}],"source_content_type":"text/x-python","patch_set":6,"id":"03229647_25ef63af","line":184,"range":{"start_line":184,"start_character":8,"end_line":184,"end_character":22},"updated":"2026-10-23 15:41:05.000000000","message":"Do you think that makes sense to have a method that checks if host metrics really match with the sum of its instances metrics? It could be always called when loading the topology to check is metrics were properly set. We can still skip if instances is empty (for tests that only use Hosts metrics(","commit_id":"30a9c12b8cf7e56b3112e50da4bcede84b7c39f9"},{"author":{"_account_id":16312,"name":"Alfredo Moralejo","email":"amoralej@redhat.com","username":"amoralej"},"change_message_id":"064c9104e17e88502f3da144a9f8dc7cd8d67edd","unresolved":true,"context_lines":[{"line_number":181,"context_line":"                vm_index +\u003d 1"},{"line_number":182,"context_line":"        return self"},{"line_number":183,"context_line":""},{"line_number":184,"context_line":"    def update_compute(self, hostname, **kwargs):"},{"line_number":185,"context_line":"        \"\"\"Update fields on the ComputeNode with the given *hostname*."},{"line_number":186,"context_line":""},{"line_number":187,"context_line":"        A ``metrics`` kwarg is merged into the node\u0027s existing"}],"source_content_type":"text/x-python","patch_set":6,"id":"bd7523b9_c7e78f53","line":184,"range":{"start_line":184,"start_character":8,"end_line":184,"end_character":22},"in_reply_to":"03229647_25ef63af","updated":"2026-10-26 14:20:06.000000000","message":"it\u0027s tricky given that the compute node may have its own resources consumption in addition. We may make check that compute-usate is \u003e\u003d instances usage. How would you propose to implement it? with a checker function that we may assert in the tests?\n\nself.ssertTrue(ComputeTopology.check_consistent_metrics())\n\nchecking it automatically in update_compute or update_instance may require specific ordering when calling the methods (i.e. we would always need to update compute first, etc...).\n\nwdyt?","commit_id":"30a9c12b8cf7e56b3112e50da4bcede84b7c39f9"},{"author":{"_account_id":30002,"name":"Douglas Viroel","email":"viroel@gmail.com","username":"dviroel"},"change_message_id":"38c364c787b95b9f0803c5e5374acb7bed4f1b1b","unresolved":true,"context_lines":[{"line_number":195,"context_line":"            if node.hostname \u003d\u003d hostname:"},{"line_number":196,"context_line":"                metrics \u003d kwargs.pop(\u0027metrics\u0027, None)"},{"line_number":197,"context_line":"                if metrics:"},{"line_number":198,"context_line":"                    node.metrics.update(metrics)"},{"line_number":199,"context_line":"                for k, v in kwargs.items():"},{"line_number":200,"context_line":"                    setattr(node, k, v)"},{"line_number":201,"context_line":"                return self"}],"source_content_type":"text/x-python","patch_set":6,"id":"e834a40c_bfb5c477","line":198,"range":{"start_line":198,"start_character":0,"end_line":198,"end_character":48},"updated":"2026-10-23 15:41:05.000000000","message":"Ok to provide the host metrics since it would need to be done when writing the test, to really draw the expected scenario (balanced, imbalanced). We may provide in the future a instance migration simulation, where topology could automatically be updated, not only instance and host relation but also host metrics. Not sure if we would really need that at some point.","commit_id":"30a9c12b8cf7e56b3112e50da4bcede84b7c39f9"},{"author":{"_account_id":16312,"name":"Alfredo Moralejo","email":"amoralej@redhat.com","username":"amoralej"},"change_message_id":"064c9104e17e88502f3da144a9f8dc7cd8d67edd","unresolved":true,"context_lines":[{"line_number":195,"context_line":"            if node.hostname \u003d\u003d hostname:"},{"line_number":196,"context_line":"                metrics \u003d kwargs.pop(\u0027metrics\u0027, None)"},{"line_number":197,"context_line":"                if metrics:"},{"line_number":198,"context_line":"                    node.metrics.update(metrics)"},{"line_number":199,"context_line":"                for k, v in kwargs.items():"},{"line_number":200,"context_line":"                    setattr(node, k, v)"},{"line_number":201,"context_line":"                return self"}],"source_content_type":"text/x-python","patch_set":6,"id":"9d1bcc2d_9b191372","line":198,"range":{"start_line":198,"start_character":0,"end_line":198,"end_character":48},"in_reply_to":"e834a40c_bfb5c477","updated":"2026-10-26 14:20:06.000000000","message":"All the functional tests are currently isolated and the topology is recreated from scratch so i don\u0027t see a case where that would be needed in a close future, although we may implemented if needed.","commit_id":"30a9c12b8cf7e56b3112e50da4bcede84b7c39f9"}],"watcher/tests/local_fixtures/prometheus.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":"504b596dda4368e151cc192a27d0afbbb7a4a2c2","unresolved":false,"context_lines":[{"line_number":77,"context_line":"        self._instances \u003d instances"},{"line_number":78,"context_line":"        self._json_path \u003d json_path"},{"line_number":79,"context_line":"        self.prometheus_emulator \u003d None"},{"line_number":80,"context_line":"        self.prometheus_url \u003d None"},{"line_number":81,"context_line":""},{"line_number":82,"context_line":"    def setUp(self):"},{"line_number":83,"context_line":"        super().setUp()"}],"source_content_type":"text/x-python","patch_set":4,"id":"f117f493_41ccee07","line":80,"updated":"2026-07-02 19:50:17.000000000","message":"PrometheusFixture stores self.prometheus_emulator and self.prometheus_url but the fixture never references self.prometheus_url after setUp; it is only set for external inspection, yet no test reads it.\n\n**Severity**: SUGGESTION | **Confidence**: 0.7\n\n**Benefit**: Removing the unused attribute (or documenting it as an inspection hook) keeps the fixture surface minimal and avoids implying tests should construct URLs manually when wsgi-intercept already handles routing.\n\n**Recommendation**:\nEither add a comment that prometheus_url is exposed for debugging/inspection, or drop the attribute since the CONF overrides are what actually route requests through wsgi-intercept.","commit_id":"8b7938f71a7b660b6cc8f1b3d15da62591faed9d"},{"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":"46229ec412a7dce001b50cf3ac8c20dfcc75a6e5","unresolved":false,"context_lines":[{"line_number":27,"context_line":"            topology.ComputeTopology()"},{"line_number":28,"context_line":"            .add_computes(count\u003d2)"},{"line_number":29,"context_line":"            .add_instances(computes\u003d[\u0027compute-1\u0027], count\u003d2)"},{"line_number":30,"context_line":"            .update_compute(\u0027compute-1\u0027, cpu\u003d80.0, ram\u003d16384000.0)"},{"line_number":31,"context_line":"            .update_instance(\u0027vm-1\u0027, cpu\u003d45.0, ram\u003d2048.0)"},{"line_number":32,"context_line":"        )"},{"line_number":33,"context_line":"        USE_PROMETHEUS \u003d True"}],"source_content_type":"text/x-python","patch_set":5,"id":"adf92e4e_ab4b0736","line":30,"updated":"2026-10-09 08:41:34.000000000","message":"The module docstring of watcher/tests/local_fixtures/prometheus.py, which is the canonical \u0027Usage in tests\u0027 example for the new fixture, uses .update_compute(\u0027compute-1\u0027, cpu\u003d80.0, ram\u003d16384000.0) and .update_instance(\u0027vm-1\u0027, cpu\u003d45.0, ram\u003d2048.0). Everywhere else in this change (topology.py module and class docstrings, the emulator docstrings, and testing.rst) cpu is a 0-1 fraction and ram is MiB with host.ram \u003d sum(inst.ram). Fed through load_from_topology(), these values become 8000% and 4500% CPU and 16384000 MiB of host RAM - roughly 500x the emulated host\u0027s 32768 MiB of physical memory.\n\n**Severity**: WARNING | **Confidence**: 0.9\n\n**Impact**: Test authors copying the canonical usage example produce physically impossible metrics (thousands of percent CPU, 500x host memory), yielding meaningless standard deviations and audits that do not reflect the intended scenario. It also undermines the normalisation convention this change goes out of its way to document.\n\n**Suggestion**:\nFix the example to fraction/MiB values consistent with the convention, e.g. .update_compute(\u0027compute-1\u0027, cpu\u003d0.80, ram\u003d13107.2) and .update_instance(\u0027vm-1\u0027, cpu\u003d0.45, ram\u003d2048.0), matching the example already used in testing.rst.","commit_id":"9dd0eb885df0afc7035e4f116eb8628d7883a39e"}],"watcher/tests/local_fixtures/prometheus_api_emulator.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":"504b596dda4368e151cc192a27d0afbbb7a4a2c2","unresolved":false,"context_lines":[{"line_number":148,"context_line":"        \"\"\""},{"line_number":149,"context_line":"        with open(path) as f:"},{"line_number":150,"context_line":"            data \u003d jsonutils.load(f)"},{"line_number":151,"context_line":"        self.load_metrics("},{"line_number":152,"context_line":"            hosts\u003ddata.get(\u0027hosts\u0027), instances\u003ddata.get(\u0027instances\u0027)"},{"line_number":153,"context_line":"        )"},{"line_number":154,"context_line":""}],"source_content_type":"text/x-python","patch_set":4,"id":"04390793_aa84efdf","line":151,"updated":"2026-07-02 19:50:17.000000000","message":"load_from_json uses oslo_serialization.jsonutils.load instead of the stdlib json module; jsonutils is an oslo convenience for i18n-aware payloads but adds no value for a plain local metrics file.\n\n**Severity**: SUGGESTION | **Confidence**: 0.6\n\n**Benefit**: Using the stdlib json module would be marginally simpler and avoids implying oslo semantics (like unicode handling) that are irrelevant here. This is a minor consistency point; jsonutils is acceptable if the project prefers oslo conventions throughout.\n\n**Recommendation**:\nConsider \u0027import json\u0027 and json.load(f) for plain JSON metric files, unless the project convention is to use jsonutils everywhere in tests.","commit_id":"8b7938f71a7b660b6cc8f1b3d15da62591faed9d"},{"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":"504b596dda4368e151cc192a27d0afbbb7a4a2c2","unresolved":false,"context_lines":[{"line_number":158,"context_line":"        \"\"\"Identify the metric kind and lookup key from a PromQL query."},{"line_number":159,"context_line":""},{"line_number":160,"context_line":"        Returns (kind, key) where kind is one of: instance_ram,"},{"line_number":161,"context_line":"        instance_cpu, host_cpu, host_ram, host_ram_total; and key"},{"line_number":162,"context_line":"        is the UUID or FQDN used for lookup."},{"line_number":163,"context_line":"        \"\"\""},{"line_number":164,"context_line":"        if \u0027ceilometer_memory_usage\u0027 in query:"}],"source_content_type":"text/x-python","patch_set":4,"id":"a9139f95_9e2f8d7a","line":161,"updated":"2026-07-02 19:50:17.000000000","message":"_identify_query docstring claims it can return kind \u0027host_ram_total\u0027, but no code path ever returns that value; the only RAM kind returned is \u0027host_ram\u0027. The docstring is misleading.\n\n**Severity**: WARNING | **Confidence**: 0.9\n\n**Impact**: A maintainer reading the docstring will expect a host_ram_total kind and may write code against it, then find it never occurs, leading to dead branches or silent no-ops (the final \u0027return None, None\u0027 fallback).\n\n**Suggestion**:\nCorrect the docstring to list only the kinds actually returned: instance_ram, instance_cpu, host_cpu, host_ram. Remove the spurious \u0027host_ram_total\u0027 entry.","commit_id":"8b7938f71a7b660b6cc8f1b3d15da62591faed9d"},{"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":"504b596dda4368e151cc192a27d0afbbb7a4a2c2","unresolved":false,"context_lines":[{"line_number":178,"context_line":""},{"line_number":179,"context_line":"        if ("},{"line_number":180,"context_line":"            \u0027node_memory_MemTotal_bytes\u0027 in query"},{"line_number":181,"context_line":"            or \u0027node_memory_MemAvailable_bytes\u0027 in query"},{"line_number":182,"context_line":"        ):"},{"line_number":183,"context_line":"            m \u003d FQDN_RE.search(query)"},{"line_number":184,"context_line":"            if m:"}],"source_content_type":"text/x-python","patch_set":4,"id":"cb97dfe7_ade35206","line":181,"updated":"2026-07-02 19:50:17.000000000","message":"_identify_query maps both node_memory_MemTotal_bytes (capacity) and node_memory_MemAvailable_bytes (available) to the same \u0027host_ram\u0027 kind returning host[\u0027ram\u0027] (usage), conflating total capacity with used memory.\n\n**Severity**: WARNING | **Confidence**: 0.8\n\n**Impact**: The real Prometheus host-RAM query (prometheus_base.py:303-310) is a compound \u0027(MemTotal - MemAvailable) / 1024\u0027. The emulator short-circuits it to one lookup, which works today, but any future code querying MemTotal alone (capacity) would receive the usage value, silently producing wrong results.\n\n**Suggestion**:\nEither document explicitly in _identify_query that the compound query is intentionally collapsed to a single usage lookup, or distinguish the two meters: store a separate \u0027ram_total\u0027 field per host and return it for MemTotal queries while returning usage for MemAvailable. At minimum update the _identify_query docstring which lists a non-existent \u0027host_ram_total\u0027 kind.","commit_id":"8b7938f71a7b660b6cc8f1b3d15da62591faed9d"},{"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":"504b596dda4368e151cc192a27d0afbbb7a4a2c2","unresolved":false,"context_lines":[{"line_number":218,"context_line":"            query \u003d request.args.get(\u0027query\u0027, \u0027\u0027)"},{"line_number":219,"context_line":"            kind, key \u003d self._identify_query(query)"},{"line_number":220,"context_line":""},{"line_number":221,"context_line":"            if kind \u003d\u003d \u0027instance_ram\u0027:"},{"line_number":222,"context_line":"                inst \u003d self.instances.get(key)"},{"line_number":223,"context_line":"                if inst is None:"},{"line_number":224,"context_line":"                    return jsonify(self._prom_empty())"}],"source_content_type":"text/x-python","patch_set":4,"id":"9caa17ea_4919965c","line":221,"updated":"2026-07-02 19:50:17.000000000","message":"The query handler uses four independent \u0027if kind \u003d\u003d\u0027 blocks (lines 221-247) each returning, rather than elif chains. The instance_cpu block is reachable after instance_ram already matched but returned None key, which is harmless but makes the control flow harder to reason about.\n\n**Severity**: WARNING | **Confidence**: 0.7\n\n**Impact**: Independent ifs with returns are correct here, but a future edit that removes an early return could accidentally fall through to a later branch, producing the wrong metric. An elif chain or a dispatch dict makes the mutual exclusivity explicit and self-documenting.\n\n**Suggestion**:\nConvert the sequential \u0027if kind \u003d\u003d\u0027 blocks into an elif chain, or refactor to a dispatch dictionary mapping kind to a (lookup_dict, value_key, labels) tuple. This documents that exactly one branch fires per query.","commit_id":"8b7938f71a7b660b6cc8f1b3d15da62591faed9d"},{"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":"504b596dda4368e151cc192a27d0afbbb7a4a2c2","unresolved":false,"context_lines":[{"line_number":355,"context_line":"            \u0027--metrics)\u0027"},{"line_number":356,"context_line":"        )"},{"line_number":357,"context_line":""},{"line_number":358,"context_line":"    emulator.app.run("},{"line_number":359,"context_line":"        host\u003dargs.host, port\u003dargs.port, debug\u003dargs.debug, ssl_context\u003dssl_ctx"},{"line_number":360,"context_line":"    )"},{"line_number":361,"context_line":""}],"source_content_type":"text/x-python","patch_set":4,"id":"c28b8447_df957405","line":358,"updated":"2026-07-02 19:50:17.000000000","message":"main() passes debug\u003dargs.debug directly to Flask app.run(); with --debug the Werkzeug reloader and interactive debugger are enabled, which is fine for a local debugging tool but the --debug flag should be documented as enabling the interactive PIN debugger.\n\n**Severity**: SUGGESTION | **Confidence**: 0.7\n\n**Benefit**: Clearer documentation prevents a contributor from running --debug on a shared host and exposing the Werkzeug debugger. This is a standalone debug entry point (never used by the test suite via wsgi-intercept) so the risk is low, but a one-line help-text note improves safety.\n\n**Recommendation**:\nAdd a note to the --debug argparse help string, e.g. help\u003d\u0027Enable Flask debug mode (Werkzeug reloader + interactive debugger; do not use on shared hosts)\u0027.","commit_id":"8b7938f71a7b660b6cc8f1b3d15da62591faed9d"},{"author":{"_account_id":30002,"name":"Douglas Viroel","email":"viroel@gmail.com","username":"dviroel"},"change_message_id":"38c364c787b95b9f0803c5e5374acb7bed4f1b1b","unresolved":true,"context_lines":[{"line_number":266,"context_line":"        self.reset()"},{"line_number":267,"context_line":"        self.load_metrics(hosts\u003dhosts, instances\u003dinstances)"},{"line_number":268,"context_line":""},{"line_number":269,"context_line":"    def load_from_topology(self, topology, fqdn_suffix\u003d\u0027.example.com\u0027):"},{"line_number":270,"context_line":"        \"\"\"Derive Prometheus metrics from a ComputeTopology object."},{"line_number":271,"context_line":""},{"line_number":272,"context_line":"        Uses the ``metrics[\u0027cpu\u0027]`` and ``metrics[\u0027ram\u0027]`` entries"}],"source_content_type":"text/x-python","patch_set":6,"id":"f4ccdef8_b01e8ac2","line":269,"range":{"start_line":269,"start_character":8,"end_line":269,"end_character":26},"updated":"2026-10-23 15:41:05.000000000","message":"Ack, I agree that here we should only do units conversion if needed, no topology specific logic should be added in this layer.","commit_id":"30a9c12b8cf7e56b3112e50da4bcede84b7c39f9"}]}
