Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package openQA for openSUSE:Factory checked 
in at 2026-02-21 21:02:36
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/openQA (Old)
 and      /work/SRC/openSUSE:Factory/.openQA.new.1977 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "openQA"

Sat Feb 21 21:02:36 2026 rev:808 rq:1334235 version:5.1771589939.8f8502b4

Changes:
--------
--- /work/SRC/openSUSE:Factory/openQA/openQA.changes    2026-02-20 
17:51:33.253847033 +0100
+++ /work/SRC/openSUSE:Factory/.openQA.new.1977/openQA.changes  2026-02-21 
21:04:37.747453993 +0100
@@ -1,0 +2,17 @@
+Fri Feb 20 17:09:47 UTC 2026 - [email protected]
+
+- Update to version 5.1771589939.8f8502b4:
+  * feat: Improve default `PRODUCTDIR` after ef229dc2
+  * refactor(ui): simplify removal of empty query parameters (after rebase)
+  * test(45-make-update-deps): allow bypassing dependency update check
+  * fix(test): improve UI test robustness by using state-based waiting
+  * test: Improve workaround for candidates menu not opening sometimes
+  * docs: Mention use of relative paths in `CASEDIR` to avoid symlinking
+  * fix: Fix wrong uses of "checkout" that should be "check out"
+  * feat: support filtering by meta-results+states in /tests/overview
+  * Revert "feat: Add symlink for aeon in openqa-bootstrap script"
+  * fix(43-scheduling-and-worker-scalability): prevent sporadic issues
+  * refactor: use join for properties in determine_free_workers
+  * fix: do not cache websocket_api_version if not set
+
+-------------------------------------------------------------------

Old:
----
  openQA-5.1771473096.98530511.obscpio

New:
----
  openQA-5.1771589939.8f8502b4.obscpio

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ openQA-client-test.spec ++++++
--- /var/tmp/diff_new_pack.9RcvFQ/_old  2026-02-21 21:04:39.395521891 +0100
+++ /var/tmp/diff_new_pack.9RcvFQ/_new  2026-02-21 21:04:39.399522056 +0100
@@ -18,7 +18,7 @@
 
 %define         short_name openQA-client
 Name:           %{short_name}-test
-Version:        5.1771473096.98530511
+Version:        5.1771589939.8f8502b4
 Release:        0
 Summary:        Test package for %{short_name}
 License:        GPL-2.0-or-later

++++++ openQA-devel-test.spec ++++++
--- /var/tmp/diff_new_pack.9RcvFQ/_old  2026-02-21 21:04:39.435523539 +0100
+++ /var/tmp/diff_new_pack.9RcvFQ/_new  2026-02-21 21:04:39.435523539 +0100
@@ -18,7 +18,7 @@
 
 %define         short_name openQA-devel
 Name:           %{short_name}-test
-Version:        5.1771473096.98530511
+Version:        5.1771589939.8f8502b4
 Release:        0
 Summary:        Test package for %{short_name}
 License:        GPL-2.0-or-later

++++++ openQA-test.spec ++++++
--- /var/tmp/diff_new_pack.9RcvFQ/_old  2026-02-21 21:04:39.475525187 +0100
+++ /var/tmp/diff_new_pack.9RcvFQ/_new  2026-02-21 21:04:39.475525187 +0100
@@ -18,7 +18,7 @@
 
 %define         short_name openQA
 Name:           %{short_name}-test
-Version:        5.1771473096.98530511
+Version:        5.1771589939.8f8502b4
 Release:        0
 Summary:        Test package for openQA
 License:        GPL-2.0-or-later

++++++ openQA-worker-test.spec ++++++
--- /var/tmp/diff_new_pack.9RcvFQ/_old  2026-02-21 21:04:39.503526341 +0100
+++ /var/tmp/diff_new_pack.9RcvFQ/_new  2026-02-21 21:04:39.507526506 +0100
@@ -18,7 +18,7 @@
 
 %define         short_name openQA-worker
 Name:           %{short_name}-test
-Version:        5.1771473096.98530511
+Version:        5.1771589939.8f8502b4
 Release:        0
 Summary:        Test package for %{short_name}
 License:        GPL-2.0-or-later

++++++ openQA.spec ++++++
--- /var/tmp/diff_new_pack.9RcvFQ/_old  2026-02-21 21:04:39.551528319 +0100
+++ /var/tmp/diff_new_pack.9RcvFQ/_new  2026-02-21 21:04:39.555528483 +0100
@@ -99,7 +99,7 @@
 %define devel_requires %devel_no_selenium_requires chromedriver
 
 Name:           openQA
-Version:        5.1771473096.98530511
+Version:        5.1771589939.8f8502b4
 Release:        0
 Summary:        The openQA web-frontend, scheduler and tools
 License:        GPL-2.0-or-later

++++++ openQA-5.1771473096.98530511.obscpio -> 
openQA-5.1771589939.8f8502b4.obscpio ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openQA-5.1771473096.98530511/assets/javascripts/filter_form.js 
new/openQA-5.1771589939.8f8502b4/assets/javascripts/filter_form.js
--- old/openQA-5.1771473096.98530511/assets/javascripts/filter_form.js  
2026-02-19 04:51:36.000000000 +0100
+++ new/openQA-5.1771589939.8f8502b4/assets/javascripts/filter_form.js  
2026-02-20 13:18:59.000000000 +0100
@@ -32,7 +32,7 @@
 
       // optimize results and states to use negative filters if shorter
       ['result', 'state'].forEach(key => {
-        const checkboxes = 
Array.from(filterForm.querySelectorAll(`input[name="${key}"]`));
+        const checkboxes = 
Array.from(filterForm.querySelectorAll(`input[name="${key}"]:not(.filter-meta)`));
         const checked = checkboxes.filter(cb => cb.checked);
         const unchecked = checkboxes.filter(cb => !cb.checked);
         if (checked.length > 1 && unchecked.length > 0 && unchecked.length < 
checked.length) {
@@ -42,12 +42,31 @@
       });
 
       const params = new URLSearchParams(formData);
-      const keysToDelete = [];
-      params.forEach((val, key) => {
-        if (val === '') keysToDelete.push(key);
-      });
-      keysToDelete.forEach(key => params.delete(key));
-      const newQuery = params.toString();
+
+      // remove redundant constituent values if meta-values are present
+      if (options && options.metaMapping) {
+        ['result', 'state'].forEach(key => {
+          const mapping = options.metaMapping[key];
+          if (!mapping) return;
+          const currentValues = params.getAll(key);
+          if (currentValues.length === 0) return;
+
+          let newValues = [...currentValues];
+          Object.keys(mapping).forEach(metaValue => {
+            if (currentValues.includes(metaValue)) {
+              const constituents = mapping[metaValue];
+              newValues = newValues.filter(val => !constituents.includes(val));
+            }
+          });
+
+          if (newValues.length !== currentValues.length) {
+            params.delete(key);
+            newValues.forEach(val => params.append(key, val));
+          }
+        });
+      }
+
+      const newQuery = new URLSearchParams(Array.from(params).filter(([, 
value]) => value !== '')).toString();
 
       if (newQuery !== currentQuery) {
         // show progress indication
@@ -87,7 +106,7 @@
   const updateMasterCheckbox = function (container) {
     const master = container.querySelector('.filter-bulk-master');
     if (!master) return;
-    const checkboxes = 
container.querySelectorAll('input[type="checkbox"]:not(.filter-bulk-master)');
+    const checkboxes = 
container.querySelectorAll('input[type="checkbox"]:not(.filter-bulk-master):not(.filter-meta)');
     const checkedCount = Array.from(checkboxes).filter(cb => 
cb.checked).length;
 
     if (checkedCount === 0) {
@@ -108,7 +127,7 @@
       if (master) {
         const mb3 = master.closest('.mb-3');
         const isChecked = master.checked;
-        
mb3.querySelectorAll('input[type="checkbox"]:not(.filter-bulk-master)').forEach(cb
 => {
+        
mb3.querySelectorAll('input[type="checkbox"]:not(.filter-bulk-master):not(.filter-meta)').forEach(cb
 => {
           cb.checked = isChecked;
         });
         return;
@@ -118,7 +137,7 @@
       if (invert) {
         e.preventDefault();
         const mb3 = invert.closest('.mb-3');
-        
mb3.querySelectorAll('input[type="checkbox"]:not(.filter-bulk-master)').forEach(cb
 => {
+        
mb3.querySelectorAll('input[type="checkbox"]:not(.filter-bulk-master):not(.filter-meta)').forEach(cb
 => {
           cb.checked = !cb.checked;
         });
         updateMasterCheckbox(mb3);
@@ -126,13 +145,37 @@
     });
 
     container.addEventListener('change', function (e) {
-      if (e.target.matches('input[type="checkbox"]:not(.filter-bulk-master)')) 
{
+      if 
(e.target.matches('input[type="checkbox"]:not(.filter-bulk-master):not(.filter-meta)'))
 {
         updateMasterCheckbox(e.target.closest('.mb-3'));
       }
     });
 
     updateMasterCheckbox(container);
   });
+
+  if (options && options.metaMapping) {
+    const filterForm = document.getElementById('filter-form');
+    if (filterForm) {
+      ['result', 'state'].forEach(key => {
+        const mapping = options.metaMapping[key];
+        if (!mapping) return;
+        Object.keys(mapping).forEach(metaValue => {
+          const metaCheckbox = 
filterForm.querySelector(`input[name="${key}"][value="${metaValue}"]`);
+          if (!metaCheckbox) return;
+          metaCheckbox.addEventListener('change', function () {
+            const isChecked = this.checked;
+            mapping[metaValue].forEach(val => {
+              const cb = 
filterForm.querySelector(`input[name="${key}"][value="${val}"]`);
+              if (cb) {
+                cb.checked = isChecked;
+                cb.dispatchEvent(new Event('change', {bubbles: true}));
+              }
+            });
+          });
+        });
+      });
+    }
+  }
 }
 
 function parseFilterArguments(paramHandler) {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openQA-5.1771473096.98530511/assets/javascripts/overview.js 
new/openQA-5.1771589939.8f8502b4/assets/javascripts/overview.js
--- old/openQA-5.1771473096.98530511/assets/javascripts/overview.js     
2026-02-19 04:51:36.000000000 +0100
+++ new/openQA-5.1771589939.8f8502b4/assets/javascripts/overview.js     
2026-02-20 13:18:59.000000000 +0100
@@ -120,7 +120,7 @@
     initCollapsedParallelChildren(relatedRow, relatedTable, 
dependencyInfo.parents.Parallel);
 }
 
-function setupOverview() {
+function setupOverview(options) {
   setupLazyLoadingFailedSteps();
   $('.timeago').timeago();
   $('.cancel').bind('ajax:success', function (event, xhr, status) {
@@ -198,7 +198,7 @@
   ensureParallelParentsComeFirst();
   collapseOkParallelChildren();
 
-  setupFilterForm();
+  setupFilterForm(options);
   const form = document.getElementById('filter-form');
   form.todo = false;
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openQA-5.1771473096.98530511/docs/ContainerizedSetup.asciidoc 
new/openQA-5.1771589939.8f8502b4/docs/ContainerizedSetup.asciidoc
--- old/openQA-5.1771473096.98530511/docs/ContainerizedSetup.asciidoc   
2026-02-19 04:51:36.000000000 +0100
+++ new/openQA-5.1771589939.8f8502b4/docs/ContainerizedSetup.asciidoc   
2026-02-20 13:18:59.000000000 +0100
@@ -56,7 +56,7 @@
 container (so you do not have any dependency on your host system) or to leave
 out the `openqa_data` container altogether (so you have only `webui` and
 `worker` containers and data is loaded and saved completely into your host
-system). If this is what you prefer, checkout the sections
+system). If this is what you prefer, check out the sections
 
<<ContainerizedSetup.asciidoc#_keeping_all_data_in_the_data_volume_container,Keeping
 all data in the Data Volume Container>>
 and
 <<ContainerizedSetup.asciidoc#_keeping_all_data_on_the_host_system,Keeping all 
data on the host system>>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openQA-5.1771473096.98530511/docs/Contributing.asciidoc 
new/openQA-5.1771589939.8f8502b4/docs/Contributing.asciidoc
--- old/openQA-5.1771473096.98530511/docs/Contributing.asciidoc 2026-02-19 
04:51:36.000000000 +0100
+++ new/openQA-5.1771589939.8f8502b4/docs/Contributing.asciidoc 2026-02-20 
13:18:59.000000000 +0100
@@ -244,14 +244,14 @@
 
 The following explains in detail what is necessary to develop openQA code.
 
-For a setup with containers you can checkout the
+For a setup with containers you can check out the
 <<Contributing.asciidoc#quick-container-development-setup,Quick container
 development setup>> below with a complete list of instructions.
 
 Otherwise follow the detailed steps below. This setup is applicable to a
 container environment as well as without.
 
-For developing openQA and os-autoinst itself it makes sense to checkout the
+For developing openQA and os-autoinst itself it makes sense to check out the
 <<Contributing.asciidoc#repo-urls,Git repositories>> and either execute
 existing tests or start the daemons manually.
 
@@ -818,12 +818,12 @@
 either `./script/initdb --init_database` or `./script/upgradedb 
--upgrade_database`.
 
 Migrations that affect possibly big tables should be tested against a local 
import of
-a production database to see how much time they need. Checkout the
+a production database to see how much time they need. Check out the
 <<Contributing.asciidoc#_importing_production_data,Importing production data>> 
section
 for details.
 
 A migration can cause the analyser to regress so it produces worse query plans 
leading
-to impaired performance. Checkout the
+to impaired performance. Check out the
 
<<Installing.asciidoc#_working_on_database_related_performance_problems,Working 
on database-related performance problems>>
 section for how to tackle this problem.
 
@@ -915,7 +915,7 @@
 [[run-tests-in-container]]
 === Run tests within a container
 The container used in this section of the documentation is not identical with 
the container used
-within the CI. To run tests within the CI environment locally, checkout the
+within the CI. To run tests within the CI environment locally, check out the
 <<Contributing.asciidoc#circleci-local-container,CircleCI documentation>> 
below.
 
 To run tests in a container please be sure that a container runtime
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openQA-5.1771473096.98530511/docs/GettingStarted.asciidoc 
new/openQA-5.1771589939.8f8502b4/docs/GettingStarted.asciidoc
--- old/openQA-5.1771473096.98530511/docs/GettingStarted.asciidoc       
2026-02-19 04:51:36.000000000 +0100
+++ new/openQA-5.1771589939.8f8502b4/docs/GettingStarted.asciidoc       
2026-02-20 13:18:59.000000000 +0100
@@ -300,7 +300,7 @@
 
 The client configuration can also be put under `~/.config/openqa/client.conf`.
 
-For development, checkout the section about
+For development, check out the section about
 <<Contributing.asciidoc#_customize_configuration_directory,customizing the 
configuration directory>>.
 
 ==== Drop-in configurations
@@ -397,7 +397,7 @@
 
 === Getting tests
 You can point `CASEDIR` and `NEEDLES_DIR` to Git repositories. openQA will
-checkout those repositories automatically and no manual setup is needed.
+check out those repositories automatically and no manual setup is needed.
 
 Otherwise you will need to clone tests and needles manually. For this,
 clone a subdirectory under `/var/lib/openqa/tests` for each test distribution
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openQA-5.1771473096.98530511/docs/Installing.asciidoc 
new/openQA-5.1771589939.8f8502b4/docs/Installing.asciidoc
--- old/openQA-5.1771473096.98530511/docs/Installing.asciidoc   2026-02-19 
04:51:36.000000000 +0100
+++ new/openQA-5.1771589939.8f8502b4/docs/Installing.asciidoc   2026-02-20 
13:18:59.000000000 +0100
@@ -156,10 +156,10 @@
 
https://github.com/os-autoinst/openQA/tree/master/container/worker/conf[worker/conf]
 directory listings on GitHub.
 
-To learn more about how to run workers checkout the
+To learn more about how to run workers check out the
 <<Installing.asciidoc#_run_openqa_workers,Run openQA workers section>>.
 
-For creating a first test job, checkout the
+For creating a first test job, check out the
 <<UsersGuide.asciidoc#_triggering_tests,Triggering tests section>>. Note that 
the
 commands mentioned there can also be invoked within a container, e.g.:
 
@@ -170,7 +170,7 @@
    openqa-cli --help
 ----
 
-Checkout the
+Check out the
 <<ContainerizedSetup.asciidoc#containerizedsetup,containerized setup section>>
 for more details.
 
@@ -1485,7 +1485,7 @@
 +
 IMPORTANT: Be sure to use pg_upgrade from the target version (like it is done 
here) and
 also no newer version which is possibly installed on the system as well.
-Checkout the https://www.postgresql.org/docs/current/pgupgrade.html[PostgreSQL 
documentation]
+Check out the 
https://www.postgresql.org/docs/current/pgupgrade.html[PostgreSQL documentation]
 for details.
 +
 NOTE: This step only takes a few seconds for multiple production DBs because 
the `--link`
@@ -1531,7 +1531,7 @@
 ----
 
 == Working on database-related performance problems
-Without extra setup, PostgreSQL already gathers many statistics, checkout
+Without extra setup, PostgreSQL already gathers many statistics, check out
 https://www.postgresql.org/docs/current/monitoring-stats.html[the official 
documentation].
 
 === Enable further statistics
@@ -1571,15 +1571,15 @@
    changes.
 
 === Further resources
-* Checkout
+* Check out
   https://www.postgresql.org/docs/current/sql-explain.html[the official 
documentation]
   for more details about `EXPLAIN`. There is also
   https://explain.depesz.com[service] for formatting those explanations to be
   more readable.
-* Checkout
+* Check out
   https://www.postgresql.org/docs/current/sql-vacuum.html[the official 
documentation]
   for more details about `VACUUM ANALYZE`.
-* Checkout the following
+* Check out the following
   https://www.postgresql.org/docs/current/performance-tips.html[documentation 
pages].
 
 == Filesystem layout
@@ -1664,6 +1664,9 @@
     - configurable via the test variable `CASEDIR` (see backend variables 
documentation)
     - this default is provided by openQA; when starting isotovideo manually 
the `CASEDIR` variable *must* be
       initialized by hand
+    - relative paths are relative to `$sharedir/tests`; to avoid symlinking,
+      use e.g. `CASEDIR=opensuse` for `$sharedir/tests/opensuse` despite
+      differing `DISTRI`
     - might contain the sub directory `lib` for placing Perl modules used by 
the tests
 * the "product directory": contains the test schedule (`main.pm`) for a 
certain product within a test distribution
     - by default identical to the "test case directory"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openQA-5.1771473096.98530511/docs/UsersGuide.asciidoc 
new/openQA-5.1771589939.8f8502b4/docs/UsersGuide.asciidoc
--- old/openQA-5.1771473096.98530511/docs/UsersGuide.asciidoc   2026-02-19 
04:51:36.000000000 +0100
+++ new/openQA-5.1771589939.8f8502b4/docs/UsersGuide.asciidoc   2026-02-20 
13:18:59.000000000 +0100
@@ -648,7 +648,7 @@
 is carried over.
 
 NOTE: The lookup-depth is limited. The search for candidates will also stop
-early if too many different kinds of failures were seen. Checkout the
+early if too many different kinds of failures were seen. Check out the
 descriptions of the relevant settings in the `carry_over` section of
 <<GettingStarted.asciidoc#_configuration,the web UI configuration>> for 
details.
 
@@ -1019,7 +1019,7 @@
 The sub-commands provide further help, e.g. `openqa-cli api --help` contains
 a lot of examples.
 
-This section focuses on particular API use-cases. Checkout the
+This section focuses on particular API use-cases. Check out the
 <<Client.asciidoc#client,openQA client>> section for further information about
 the client itself, how authentication works and how plain `curl` can be used.
 
@@ -1341,7 +1341,7 @@
 
 Assets may be shared between the web-UI and the workers by having them 
literally use a shared
 file system (this used to be the only option), or by having the workers 
download them from the
-server when needed and cache them locally. Checkout the documentation about
+server when needed and cache them locally. Check out the documentation about
 <<Installing.asciidoc#asset-caching,asset caching>> for more on this.
 
 === Specifying assets required by a job ===
@@ -1450,7 +1450,7 @@
 <<GettingStarted.asciidoc#_configuration,the web UI configuration>>. Many other
 cleanup-related settings can be found within the web UI configuration as well,
 e.g. the `[…_limits]` sections contain various tweaks and allow to change 
certain
-defaults. Checkout the sub section
+defaults. Check out the sub section
 <<UsersGuide.asciidoc#_timers_and_triggers,Timers and triggers>> to learn more
 about how those jobs are triggered.
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openQA-5.1771473096.98530511/docs/WritingTests.asciidoc 
new/openQA-5.1771589939.8f8502b4/docs/WritingTests.asciidoc
--- old/openQA-5.1771473096.98530511/docs/WritingTests.asciidoc 2026-02-19 
04:51:36.000000000 +0100
+++ new/openQA-5.1771589939.8f8502b4/docs/WritingTests.asciidoc 2026-02-20 
13:18:59.000000000 +0100
@@ -903,7 +903,7 @@
 
 Then, in job templates, add test suite(s) and all of its dependent test
 suite(s). Keep in mind to place the machines which have been explicitly defined
-in a variable for each dependent test suite. Checkout the following example
+in a variable for each dependent test suite. Check out the following example
 sections to get a better understanding.
 
 ==== Handling of related jobs on failure / cancellation / restart
@@ -2361,7 +2361,7 @@
 
 It is also possible to create a GitHub workflow that will clone and monitor an
 openQA job which is mentioned in the PR description or comment. The scripts
-repository contains a pre-defined GitHub action for this. Checkout the
+repository contains a pre-defined GitHub action for this. Check out the
 documentation of the
 
https://github.com/os-autoinst/os-autoinst-scripts/blob/master/openqa-clone-and-monitor-job-from-pr[openqa-clone-and-monitor-job-from-pr]
 script for further information and an example configuration.
@@ -2391,7 +2391,7 @@
 created from a fork repository branch which extra configuration.
 
 The test scenarios for your repository need to be defined in the file
-`scenario-definitions.yaml` at the root of your repository. Checkout the
+`scenario-definitions.yaml` at the root of your repository. Check out the
 
https://github.com/os-autoinst/os-autoinst-distri-example/blob/master/scenario-definitions.yaml[scenario
 definitions]
 from the example distribution for an example. You may append a parameter like
 `SCENARIO_DEFINITIONS_YAML=path/of/yaml` to the query parameters of the webhook
@@ -2401,7 +2401,7 @@
 It is also possible to avoid using openQA at all and run the backend
 `isotovideo` directly within the CI runner. This simplifies the setup as no
 openQA instance is needed but of course test results cannot be examined using
-a web interface as usual. Checkout the
+a web interface as usual. Check out the
 
https://github.com/os-autoinst/os-autoinst-distri-example/blob/main/README.md#local-testing-and-ci-environment[README
 of the example test distribution]
 for more information.
 
@@ -2445,9 +2445,9 @@
 5. Keep SSL enabled. (Be sure your openQA instance is reachable via HTTPS.)
 6. Select "Let me select individual events." and then "Pull requests".
 7. Ensure "Active" is checked and confirm.
-8. GitHub should now have been delivering a "ping" event. Checkout whether
+8. GitHub should now have been delivering a "ping" event. Check out whether
    it could be delivered. If you have gotten a 200 response then everything
-   is setup correctly. Otherwise, checkout the response of the delivery to
+   is setup correctly. Otherwise, check out the response of the delivery to
    investigate what is wrong.
 
 == Integrating test results from external systems
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openQA-5.1771473096.98530511/lib/OpenQA/CacheService.pm 
new/openQA-5.1771589939.8f8502b4/lib/OpenQA/CacheService.pm
--- old/openQA-5.1771473096.98530511/lib/OpenQA/CacheService.pm 2026-02-19 
04:51:36.000000000 +0100
+++ new/openQA-5.1771589939.8f8502b4/lib/OpenQA/CacheService.pm 2026-02-20 
13:18:59.000000000 +0100
@@ -22,7 +22,7 @@
 
 sub _configure_sqlite_database ($self, $sqlite, $dbh) {
     # default to using DELETE journaling mode to avoid database corruption 
seen in production (see poo#67000)
-    # checkout https://www.sqlite.org/pragma.html#pragma_journal_mode for 
possible values
+    # check out https://www.sqlite.org/pragma.html#pragma_journal_mode for 
possible values
     my $sqlite_mode = uc($ENV{OPENQA_CACHE_SERVICE_SQLITE_JOURNAL_MODE} || 
'DELETE');
     $dbh->sqlite_busy_timeout(SQLITE_BUSY_TIMEOUT);
     $dbh->do("pragma journal_mode=$sqlite_mode");
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openQA-5.1771473096.98530511/lib/OpenQA/Jobs/Constants.pm 
new/openQA-5.1771589939.8f8502b4/lib/OpenQA/Jobs/Constants.pm
--- old/openQA-5.1771473096.98530511/lib/OpenQA/Jobs/Constants.pm       
2026-02-19 04:51:36.000000000 +0100
+++ new/openQA-5.1771589939.8f8502b4/lib/OpenQA/Jobs/Constants.pm       
2026-02-20 13:18:59.000000000 +0100
@@ -57,6 +57,7 @@
     EXECUTION => 'execution',
     FINAL => 'final',
 };
+use constant META_STATES => (PRE_EXECUTION, EXECUTION, FINAL);
 
 # results for the overall job
 use constant {
@@ -92,6 +93,24 @@
     COMPLETE => 'complete',
     NOT_COMPLETE => 'not_complete',
     ABORTED => 'aborted',
+    OK => 'ok',
+    NOT_OK => 'not_ok',
+};
+use constant META_RESULTS => (COMPLETE, NOT_COMPLETE, ABORTED, OK, NOT_OK);
+
+use constant META_MAPPING => {
+    state => {
+        PRE_EXECUTION() => [PRE_EXECUTION_STATES],
+        EXECUTION() => [EXECUTION_STATES],
+        FINAL() => [FINAL_STATES],
+    },
+    result => {
+        COMPLETE() => [COMPLETE_RESULTS],
+        NOT_COMPLETE() => [NOT_COMPLETE_RESULTS],
+        ABORTED() => [ABORTED_RESULTS],
+        OK() => [OK_RESULTS],
+        NOT_OK() => [NOT_OK_RESULTS],
+    },
 };
 
 # results for particular job modules
@@ -120,21 +139,29 @@
   CANCELLED
   COMPLETE_RESULTS
   DONE
+  EXECUTION
   EXECUTION_STATES
   FAILED
+  FINAL
   FINAL_STATES
   INCOMPLETE
+  NOT_COMPLETE
   NOT_COMPLETE_RESULTS
   ABORTED
   ABORTED_RESULTS
-  NONE
+  COMPLETE
+  COMPLETE_RESULTS
+  OK
+  OK_RESULTS
+  NOT_OK
   NOT_OK_RESULTS
+  NONE
   OBSOLETED
-  OK_RESULTS
   PARALLEL_FAILED
   PARALLEL_RESTARTED
   PASSED
   PENDING_STATES
+  PRE_EXECUTION
   PRE_EXECUTION_STATES
   PRISTINE_STATES
   RESULTS
@@ -148,6 +175,9 @@
   USER_CANCELLED
   USER_RESTARTED
   MODULE_RESULTS
+  META_RESULTS
+  META_STATES
+  META_MAPPING
   COMMON_RESULT_FILES
   TIMEOUT_EXCEEDED
   DEFAULT_JOB_PRIORITY
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openQA-5.1771473096.98530511/lib/OpenQA/Needles.pm 
new/openQA-5.1771589939.8f8502b4/lib/OpenQA/Needles.pm
--- old/openQA-5.1771473096.98530511/lib/OpenQA/Needles.pm      2026-02-19 
04:51:36.000000000 +0100
+++ new/openQA-5.1771589939.8f8502b4/lib/OpenQA/Needles.pm      2026-02-20 
13:18:59.000000000 +0100
@@ -28,7 +28,7 @@
 sub needle_temp_dir ($dir, $ref) { path($tmp_dir, basename(dirname($dir)), 
$ref, 'needles') }
 
 sub _locate_needle_for_ref ($relative_needle_path, $needles_dir, $needles_ref, 
$needle_url) {
-    # checkout needle from git - return absolute path to json file on success 
and undef on error
+    # check out needle from git - return absolute path to json file on success 
and undef on error
     return undef unless defined $needles_ref;
     my $app = OpenQA::App->singleton;
     my $allow_arbitrary_url_fetch = $app->config->{'scm 
git'}->{allow_arbitrary_url_fetch} eq 'yes';
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openQA-5.1771473096.98530511/lib/OpenQA/Scheduler/Model/Jobs.pm 
new/openQA-5.1771589939.8f8502b4/lib/OpenQA/Scheduler/Model/Jobs.pm
--- old/openQA-5.1771473096.98530511/lib/OpenQA/Scheduler/Model/Jobs.pm 
2026-02-19 04:51:36.000000000 +0100
+++ new/openQA-5.1771589939.8f8502b4/lib/OpenQA/Scheduler/Model/Jobs.pm 
2026-02-20 13:18:59.000000000 +0100
@@ -28,8 +28,14 @@
 has shuffle_workers => 1;
 
 sub determine_free_workers ($shuffle = 0) {
-    my @free_workers = grep { !$_->dead && ($_->websocket_api_version() || 0) 
== WEBSOCKET_API_VERSION }
-      OpenQA::Schema->singleton->resultset('Workers')->search({job_id => 
undef, error => undef})->all;
+    my @free_workers = grep { !$_->dead } 
OpenQA::Schema->singleton->resultset('Workers')->search(
+        {
+            job_id => undef,
+            error => undef,
+            'properties.key' => 'WEBSOCKET_API_VERSION',
+            'properties.value' => WEBSOCKET_API_VERSION
+        },
+        {join => 'properties'})->all;
     return $shuffle ? shuffle(\@free_workers) : \@free_workers;
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openQA-5.1771473096.98530511/lib/OpenQA/Schema/Result/Jobs.pm 
new/openQA-5.1771589939.8f8502b4/lib/OpenQA/Schema/Result/Jobs.pm
--- old/openQA-5.1771473096.98530511/lib/OpenQA/Schema/Result/Jobs.pm   
2026-02-19 04:51:36.000000000 +0100
+++ new/openQA-5.1771589939.8f8502b4/lib/OpenQA/Schema/Result/Jobs.pm   
2026-02-20 13:18:59.000000000 +0100
@@ -784,7 +784,7 @@
                 next if exists $jobs->{$parent_id};
                 die "Direct parent $parent_id needs to be cloned as well for 
the directly chained dependency "
                   . 'to work correctly. It is generally better to restart the 
parent which will restart all children '
-                  . 'as well. Checkout the '
+                  . 'as well. Check out the '
                   . '<a 
href="https://open.qa/docs/#_handling_of_related_jobs_on_failure_cancellation_restart";>'
                   . "documentation</a> for more information.\n"
                   if $no_directly_chained_parent;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openQA-5.1771473096.98530511/lib/OpenQA/Schema/Result/Workers.pm 
new/openQA-5.1771589939.8f8502b4/lib/OpenQA/Schema/Result/Workers.pm
--- old/openQA-5.1771473096.98530511/lib/OpenQA/Schema/Result/Workers.pm        
2026-02-19 04:51:36.000000000 +0100
+++ new/openQA-5.1771589939.8f8502b4/lib/OpenQA/Schema/Result/Workers.pm        
2026-02-20 13:18:59.000000000 +0100
@@ -127,8 +127,9 @@
 }
 
 sub websocket_api_version ($self) {
-    return $self->{_websocket_api_version} if exists 
$self->{_websocket_api_version};
-    return $self->{_websocket_api_version} = 
$self->get_property('WEBSOCKET_API_VERSION');
+    my $v = $self->{_websocket_api_version} // 
$self->get_property('WEBSOCKET_API_VERSION');
+    return $self->{_websocket_api_version} = $v if $v;
+    return undef;
 }
 
 sub check_class {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openQA-5.1771473096.98530511/lib/OpenQA/Script/CloneJob.pm 
new/openQA-5.1771589939.8f8502b4/lib/OpenQA/Script/CloneJob.pm
--- old/openQA-5.1771473096.98530511/lib/OpenQA/Script/CloneJob.pm      
2026-02-19 04:51:36.000000000 +0100
+++ new/openQA-5.1771589939.8f8502b4/lib/OpenQA/Script/CloneJob.pm      
2026-02-20 13:18:59.000000000 +0100
@@ -215,7 +215,7 @@
         api => $local_url->host,
         apikey => $options->{apikey},
         apisecret => $options->{apisecret});
-    die "API key/secret for '$options->{host}' missing. Checkout '$0 --help' 
for the config file syntax/lookup.\n"
+    die "API key/secret for '$options->{host}' missing. Check out '$0 --help' 
for the config file syntax/lookup.\n"
       if !$options->{'export-command'} && !($local->apikey && 
$local->apisecret);
 
     # configure user agents for the source host (usually a remote host)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openQA-5.1771473096.98530511/lib/OpenQA/Shared/Plugin/Gru.pm 
new/openQA-5.1771589939.8f8502b4/lib/OpenQA/Shared/Plugin/Gru.pm
--- old/openQA-5.1771473096.98530511/lib/OpenQA/Shared/Plugin/Gru.pm    
2026-02-19 04:51:36.000000000 +0100
+++ new/openQA-5.1771589939.8f8502b4/lib/OpenQA/Shared/Plugin/Gru.pm    
2026-02-20 13:18:59.000000000 +0100
@@ -321,7 +321,7 @@
             return Mojo::Promise->reject($result, 500) if ref $result eq 
'HASH' && $result->{error};
 
             # format error message (fallback for general case)
-            my $msg = ref $result eq '' && $result ? $result : 'Checkout 
Minion dashboard for further details.';
+            my $msg = ref $result eq '' && $result ? $result : 'check out 
Minion dashboard for further details.';
             return Mojo::Promise->reject({error => "Task for $task_description 
failed: $msg", result => $result}, 500);
         });
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openQA-5.1771473096.98530511/lib/OpenQA/Task/Git/Clone.pm 
new/openQA-5.1771589939.8f8502b4/lib/OpenQA/Task/Git/Clone.pm
--- old/openQA-5.1771473096.98530511/lib/OpenQA/Task/Git/Clone.pm       
2026-02-19 04:51:36.000000000 +0100
+++ new/openQA-5.1771589939.8f8502b4/lib/OpenQA/Task/Git/Clone.pm       
2026-02-20 13:18:59.000000000 +0100
@@ -121,7 +121,7 @@
     die <<~"END_OF_MESSAGE" unless $git->is_workdir_clean;
         NOT updating dirty Git checkout at '$path'.
         In case this is expected (e.g. on a development openQA instance) you 
can disable auto-updating.
-        Then the Git checkout will no longer be kept up-to-date, though. 
Checkout http://open.qa/docs/#_getting_tests for details.
+        Then the Git checkout will no longer be kept up-to-date, though. Check 
out http://open.qa/docs/#_getting_tests for details.
         END_OF_MESSAGE
 
     unless ($requested_branch) {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openQA-5.1771473096.98530511/lib/OpenQA/Utils.pm 
new/openQA-5.1771589939.8f8502b4/lib/OpenQA/Utils.pm
--- old/openQA-5.1771473096.98530511/lib/OpenQA/Utils.pm        2026-02-19 
04:51:36.000000000 +0100
+++ new/openQA-5.1771589939.8f8502b4/lib/OpenQA/Utils.pm        2026-02-20 
13:18:59.000000000 +0100
@@ -193,9 +193,9 @@
 # To be backwards compatible we need to search for all combinations of "old/new
 # testrepository name" and "old/new folder structure" within the
 # testrepository.
-sub productdir ($distri = undef, $version = undef, $rootfortests = undef) {
-    my $dir = testcasedir($distri, $version, $rootfortests);
-    return "$dir/products/$distri" if $distri && -e "$dir/products/$distri";
+sub productdir ($effective_distri = undef, $version = undef, $rootfortests = 
undef, $distri = undef) {
+    my $dir = testcasedir($effective_distri, $version, $rootfortests);
+    return "$dir/products/$distri" if ($distri //= $effective_distri) && -e 
"$dir/products/$distri";
     return $dir;
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openQA-5.1771473096.98530511/lib/OpenQA/WebAPI/Controller/Test.pm 
new/openQA-5.1771589939.8f8502b4/lib/OpenQA/WebAPI/Controller/Test.pm
--- old/openQA-5.1771473096.98530511/lib/OpenQA/WebAPI/Controller/Test.pm       
2026-02-19 04:51:36.000000000 +0100
+++ new/openQA-5.1771589939.8f8502b4/lib/OpenQA/WebAPI/Controller/Test.pm       
2026-02-20 13:18:59.000000000 +0100
@@ -918,6 +918,7 @@
         summary_category_query => \%SUMMARY_CATEGORY_QUERY,
         only_distri => $only_distri,
         limit_exceeded => $exceeded_limit,
+        meta_mapping => META_MAPPING,
     );
     $self->stash(\%stash);
     $self->respond_to(json => {json => \%stash}, html => {template => 
'test/overview'});
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openQA-5.1771473096.98530511/lib/OpenQA/WebAPI/Plugin/Helpers.pm 
new/openQA-5.1771589939.8f8502b4/lib/OpenQA/WebAPI/Plugin/Helpers.pm
--- old/openQA-5.1771473096.98530511/lib/OpenQA/WebAPI/Plugin/Helpers.pm        
2026-02-19 04:51:36.000000000 +0100
+++ new/openQA-5.1771589939.8f8502b4/lib/OpenQA/WebAPI/Plugin/Helpers.pm        
2026-02-20 13:18:59.000000000 +0100
@@ -9,7 +9,13 @@
 use OpenQA::Schema;
 use OpenQA::Utils qw(bugurl human_readable_size render_escaped_refs 
href_to_bugref);
 use OpenQA::Events;
-use OpenQA::Jobs::Constants qw(EXECUTION_STATES PRE_EXECUTION_STATES 
ABORTED_RESULTS FAILED NOT_COMPLETE_RESULTS);
+use OpenQA::Jobs::Constants qw(
+  EXECUTION_STATES PRE_EXECUTION_STATES ABORTED_RESULTS FAILED 
NOT_COMPLETE_RESULTS
+  COMPLETE NOT_COMPLETE ABORTED COMPLETE_RESULTS
+  OK NOT_OK OK_RESULTS NOT_OK_RESULTS
+  PRE_EXECUTION EXECUTION FINAL FINAL_STATES
+  META_RESULTS META_STATES META_MAPPING
+);
 use Text::Glob qw(glob_to_regex_string);
 use List::Util qw(any min);
 use Feature::Compat::Try;
@@ -518,6 +524,16 @@
     my $results = $c->every_non_empty_param('result');
     my $states_not = $c->every_non_empty_param('state__not');
     my $results_not = $c->every_non_empty_param('result__not');
+
+    # expansion of meta-values
+    my $expand = sub ($params, $meta) {
+        [map { $meta->{$_} ? @{$meta->{$_}} : $_ } @$params]
+    };
+    $states = $expand->($states, META_MAPPING->{state});
+    $results = $expand->($results, META_MAPPING->{result});
+    $states_not = $expand->($states_not, META_MAPPING->{state});
+    $results_not = $expand->($results_not, META_MAPPING->{result});
+
     my $archs = $c->every_non_empty_param('arch');
     my $machines = $c->every_non_empty_param('machine');
     my $failed_modules = $c->every_non_empty_param('failed_modules');
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openQA-5.1771473096.98530511/lib/OpenQA/Worker/Engines/isotovideo.pm 
new/openQA-5.1771589939.8f8502b4/lib/OpenQA/Worker/Engines/isotovideo.pm
--- old/openQA-5.1771473096.98530511/lib/OpenQA/Worker/Engines/isotovideo.pm    
2026-02-19 04:51:36.000000000 +0100
+++ new/openQA-5.1771589939.8f8502b4/lib/OpenQA/Worker/Engines/isotovideo.pm    
2026-02-20 13:18:59.000000000 +0100
@@ -394,7 +394,7 @@
     my $effective_distri = defined $casedir && 
!looks_like_url_with_scheme($casedir) ? $casedir : $vars->{DISTRI};
     my @vars_for_default_dirs = ($effective_distri, $vars->{VERSION}, 
$shared_cache);
     my $default_casedir = testcasedir(@vars_for_default_dirs);
-    my $default_productdir = productdir(@vars_for_default_dirs);
+    my $default_productdir = productdir(@vars_for_default_dirs, 
$vars->{DISTRI});
     my $target_name = path($default_casedir)->basename;
     my $has_custom_dir = $casedir || $vars->{PRODUCTDIR};
     $casedir = $vars->{CASEDIR} //= $absolute_paths ? $default_casedir : 
$target_name;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openQA-5.1771473096.98530511/script/openqa-auto-update 
new/openQA-5.1771589939.8f8502b4/script/openqa-auto-update
--- old/openQA-5.1771473096.98530511/script/openqa-auto-update  2026-02-19 
04:51:36.000000000 +0100
+++ new/openQA-5.1771589939.8f8502b4/script/openqa-auto-update  2026-02-20 
13:18:59.000000000 +0100
@@ -23,7 +23,7 @@
     to be considered (default: $min_mtime)
   OPENQA_PACKAGE_CACHE_REPO_GLOB: the glob to find relevant packages
     (default: $glob)
-Checkout "openqa-clean-repo-cache --help" for details.
+Check out "openqa-clean-repo-cache --help" for details.
 
 Options:
  -h, --help         display this help
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openQA-5.1771473096.98530511/script/openqa-bootstrap 
new/openQA-5.1771589939.8f8502b4/script/openqa-bootstrap
--- old/openQA-5.1771473096.98530511/script/openqa-bootstrap    2026-02-19 
04:51:36.000000000 +0100
+++ new/openQA-5.1771589939.8f8502b4/script/openqa-bootstrap    2026-02-20 
13:18:59.000000000 +0100
@@ -149,9 +149,6 @@
     if [[ ! -e /var/lib/openqa/tests/sle ]]; then
         ln -s opensuse /var/lib/openqa/tests/sle
     fi
-    if [[ ! -e /var/lib/openqa/tests/aeon ]]; then
-        ln -s opensuse /var/lib/openqa/tests/aeon
-    fi
 
     if ping -c1 gitlab.suse.de.; then
         
sles_needles_giturl="https://gitlab.suse.de/openqa/os-autoinst-needles-sles.git";
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openQA-5.1771473096.98530511/t/10-tests_overview.t 
new/openQA-5.1771589939.8f8502b4/t/10-tests_overview.t
--- old/openQA-5.1771473096.98530511/t/10-tests_overview.t      2026-02-19 
04:51:36.000000000 +0100
+++ new/openQA-5.1771589939.8f8502b4/t/10-tests_overview.t      2026-02-20 
13:18:59.000000000 +0100
@@ -467,6 +467,19 @@
     like($summary, qr/Scheduled: 2/i, 'Scheduled jobs remain');
 };
 
+subtest 'Meta-filters' => sub {
+    
$t->get_ok('/tests/overview?distri=opensuse&version=13.1&build=0091&result=complete')->status_is(200);
+    my $summary = get_summary;
+    like($summary, qr/Passed: 3/i, 'Passed jobs are included via "complete" 
meta-result');
+    
$t->get_ok('/tests/overview?distri=opensuse&version=13.1&build=0091&state=final')->status_is(200);
+    $summary = get_summary;
+    like($summary, qr/Passed: 3/i, 'Done jobs are included via "final" 
meta-state');
+    
$t->get_ok('/tests/overview?distri=opensuse&version=13.1&build=0091&result__not=complete')->status_is(200);
+    $summary = get_summary;
+    unlike($summary, qr/Passed: [1-9]/i, 'Passed jobs are excluded via NOT 
"complete"');
+    like($summary, qr/Scheduled: 2 Running: 2/i, 'Other categories remain');
+};
+
 subtest 'Maximum jobs limit' => sub {
     
$t->get_ok('/tests/overview')->status_is(200)->element_exists_not('#max-jobs-limit')
       ->element_count_is('table.overview td.name', 7);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openQA-5.1771473096.98530511/t/43-scheduling-and-worker-scalability.t 
new/openQA-5.1771589939.8f8502b4/t/43-scheduling-and-worker-scalability.t
--- old/openQA-5.1771473096.98530511/t/43-scheduling-and-worker-scalability.t   
2026-02-19 04:51:36.000000000 +0100
+++ new/openQA-5.1771589939.8f8502b4/t/43-scheduling-and-worker-scalability.t   
2026-02-20 13:18:59.000000000 +0100
@@ -148,87 +148,61 @@
 my $polling_tries_jobs = $seconds_to_wait_per_job / $polling_interval * 
$job_count;
 
 subtest 'wait for workers to be idle' => sub {
-    # wait for all workers to register
-    my @worker_search_args = ({'properties.key' => 'WEBSOCKET_API_VERSION'}, 
{join => 'properties'});
+    # wait for all workers to register, have correct API version and be idle
+    # this ensures they are fully visible to the scheduler
     my $actual_count = 0;
     for my $try (1 .. $polling_tries_workers) {
-        last if ($actual_count = $workers->search(@worker_search_args)->count) 
== $worker_count;
-        note("Waiting until all workers are registered, try $try");    # 
uncoverable statement
+        my @idle
+          = grep { $_->status eq 'idle' && ($_->websocket_api_version || 0) == 
WEBSOCKET_API_VERSION } $workers->all;
+        $actual_count = scalar @idle;
+        last if $actual_count == $worker_count;
+        note("Waiting until all workers are registered and idle, try $try");   
 # uncoverable statement
         sleep $polling_interval;    # uncoverable statement
     }
-    is $actual_count, $worker_count, 'all workers registered';
-
-    # wait for expected number of workers to become limited
-    my $limited_workers = max(0, $worker_count - $worker_limit);
-    $worker_count = min($worker_count, $worker_limit);
-    for my $try (1 .. $polling_tries_workers) {
-        last if ($actual_count = $workers->search({error => {-like => 
'%limited%'}})->count) == $limited_workers;
-        note("Waiting until $limited_workers workers are limited, try $try");  
  # uncoverable statement
-        sleep $polling_interval;    # uncoverable statement
-    }
-    is $actual_count, $limited_workers, 'expected number of workers limited';
+    is $actual_count, $worker_count, 'all workers registered and idle';
 
     # check that no workers are in unexpected offline/error states
     my @non_idle_workers;
     for my $worker ($workers->all) {
         my $is_idle = $worker->status eq 'idle';
-        my $is_idle_or_limited = $is_idle || $worker->error =~ qr/limited/;
         $worker_ids{$worker->id} = 1 if $is_idle;
         push(@non_idle_workers, $worker->info)    # uncoverable statement
-          if !$is_idle_or_limited || ($worker->websocket_api_version || 0) != 
WEBSOCKET_API_VERSION;
+          if !$is_idle || ($worker->websocket_api_version || 0) != 
WEBSOCKET_API_VERSION;
     }
-    is scalar @non_idle_workers, 0, 'all workers idling/limited' or 
always_explain \@non_idle_workers;
+    is scalar @non_idle_workers, 0, 'all workers idling' or always_explain 
\@non_idle_workers;
 };
 
 subtest 'assign and run jobs' => sub {
     my $scheduler = OpenQA::Scheduler::Model::Jobs->singleton;
-    my $allocated = $scheduler->schedule;
-    unless (ref($allocated) eq 'ARRAY' && @$allocated > 0) {
-        always_explain 'Allocated: ', $allocated;    # uncoverable statement
-        always_explain 'Scheduled: ', $scheduler->scheduled_jobs;    # 
uncoverable statement
-        BAIL_OUT('Unable to assign jobs to (idling) workers');    # 
uncoverable statement
+
+    # ensure the scheduler also sees them as free
+    for my $try (1 .. $polling_tries_workers) {
+        last if scalar 
@{OpenQA::Scheduler::Model::Jobs::determine_free_workers()} == $worker_count;
+        sleep $polling_interval;    # uncoverable statement
+    }
+
+    # retry scheduling until all workers have a job assigned (or all jobs are 
assigned)
+    my $expected_allocated = min($worker_count, $job_count);
+    for my $try (1 .. $polling_tries_workers) {
+        $scheduler->schedule;
+        last if $jobs->search({state => {-in => [ASSIGNED, SETUP, RUNNING, 
DONE]}})->count >= $expected_allocated;
+        sleep $polling_interval;    # uncoverable statement
     }
 
+    my $allocated_count = $jobs->search({state => {-in => [ASSIGNED, SETUP, 
RUNNING, DONE]}})->count;
+    ok($allocated_count >= $expected_allocated, 'all workers have a job or all 
jobs assigned')
+      or diag("Allocated count: $allocated_count, expected at least: 
$expected_allocated");
+
     my $remaining_jobs = $job_count - $worker_count;
-    note('Assigned jobs: ' . dumper($allocated));
     note('Remaining ' . ($remaining_jobs > 0 ? ('jobs: ' . $remaining_jobs) : 
('workers: ' . -$remaining_jobs)));
-    if ($remaining_jobs > 0) {
-        is(scalar @$allocated, $worker_count, 'each worker has a job 
assigned');
-    }
-    elsif ($remaining_jobs < 0) {
-        # uncoverable statement only executed when there are more jobs than 
workers based config parameters
-        is(scalar @$allocated, $job_count, 'each job has a worker assigned');
-    }
-    else {
-        # uncoverable statement only executed when the number of workers and 
jobs are equal based on config parameters
-        is(scalar @$allocated, $job_count, 'all jobs assigned and all workers 
busy');
-        # uncoverable statement count:1
-        # uncoverable statement count:2
-        my @allocated_job_ids = map { $_->{job} } @$allocated;
-        # uncoverable statement count:1
-        # uncoverable statement count:2
-        my @allocated_worker_ids = map { $_->{worker} } @$allocated;
-        # uncoverable statement count:1
-        # uncoverable statement count:2
-        my @expected_job_ids = map { int($_) } keys %job_ids;
-        # uncoverable statement count:1
-        # uncoverable statement count:2
-        my @expected_worker_ids = map { int($_) } keys %worker_ids;
-        # uncoverable statement
-        is_deeply([sort @allocated_job_ids], [sort @expected_job_ids], 'all 
jobs allocated');
-        # uncoverable statement
-        is_deeply([sort @allocated_worker_ids], [sort @expected_worker_ids], 
'all workers allocated');
-    }
+
     for my $try (1 .. $polling_tries_jobs) {
         my $done_count = $jobs->search({state => DONE})->count;
         last if $done_count == $job_count;
         my $scheduled_count = $jobs->search({state => SCHEDULED})->count;
         if ($scheduled_count > 0) {
             note("Trying to assign $scheduled_count scheduled jobs");
-            if (my $allocated = 
OpenQA::Scheduler::Model::Jobs->singleton->schedule) {
-                my $assigned_job_count = scalar @$allocated;
-                note("Assigned $assigned_job_count more jobs: " . 
dumper($allocated)) if $assigned_job_count > 0;
-            }
+            OpenQA::Scheduler::Model::Jobs->singleton->schedule;
         }
         note("Waiting until all jobs are done ($done_count/$job_count), try 
$try");
         sleep $polling_interval;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openQA-5.1771473096.98530511/t/45-make-update-deps.t 
new/openQA-5.1771589939.8f8502b4/t/45-make-update-deps.t
--- old/openQA-5.1771473096.98530511/t/45-make-update-deps.t    2026-02-19 
04:51:36.000000000 +0100
+++ new/openQA-5.1771589939.8f8502b4/t/45-make-update-deps.t    2026-02-20 
13:18:59.000000000 +0100
@@ -6,6 +6,8 @@
 use Test::Warnings;
 # no OpenQA::Test::TimeLimit for this trivial test
 
+plan skip_all => 'SKIP_UPDATE_DEPS is set' if $ENV{SKIP_UPDATE_DEPS};
+
 my $make = 'make update-deps';
 my @out = qx{$make};
 my $rc = $?;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openQA-5.1771473096.98530511/t/ui/10-tests_overview.t 
new/openQA-5.1771589939.8f8502b4/t/ui/10-tests_overview.t
--- old/openQA-5.1771473096.98530511/t/ui/10-tests_overview.t   2026-02-19 
04:51:36.000000000 +0100
+++ new/openQA-5.1771589939.8f8502b4/t/ui/10-tests_overview.t   2026-02-20 
13:18:59.000000000 +0100
@@ -696,18 +696,20 @@
     my $master = $driver->find_child_element($results_div, 
'.filter-bulk-master');
     subtest 'select all' => sub {
         $master->click();
-        my @checkboxes = $driver->find_child_elements($results_div, 
'input[type="checkbox"]:not(.filter-bulk-master)');
+        my @checkboxes = $driver->find_child_elements($results_div,
+            
'input[type="checkbox"]:not(.filter-bulk-master):not(.filter-meta)');
         my $all_selected = 1;
         for my $cb (@checkboxes) { $all_selected = 0 unless $cb->is_selected; }
-        ok $all_selected, 'all checkboxes selected after master checkbox 
click';
+        ok $all_selected, 'all base checkboxes selected after master checkbox 
click';
         ok $master->is_selected, 'master checkbox is checked';
     };
     subtest 'select none' => sub {
         $master->click();
-        my @checkboxes = $driver->find_child_elements($results_div, 
'input[type="checkbox"]:not(.filter-bulk-master)');
+        my @checkboxes = $driver->find_child_elements($results_div,
+            
'input[type="checkbox"]:not(.filter-bulk-master):not(.filter-meta)');
         my $none_selected = 1;
         for my $cb (@checkboxes) { $none_selected = 0 if $cb->is_selected; }
-        ok $none_selected, 'all checkboxes deselected after master checkbox 
click again';
+        ok $none_selected, 'all base checkboxes deselected after master 
checkbox click again';
         ok !$master->is_selected, 'master checkbox is unchecked';
     };
     subtest 'partially selected' => sub {
@@ -792,6 +794,79 @@
     unlike $url, qr/machine=/, 'URL does not contain empty machine parameter';
 };
 
+subtest 'meta-filter checkboxes' => sub {
+    $driver->get('/tests/overview');
+    $driver->find_element('#filter-panel .card-header')->click();
+    wait_for_element(selector => '#filter-complete', is_displayed => 1);
+    ok $driver->find_element_by_id('filter-complete'), 'complete meta-result 
checkbox present';
+    ok $driver->find_element_by_id('filter-final'), 'final meta-state checkbox 
present';
+    $driver->find_element_by_id('filter-complete')->click();
+    $driver->find_element('#filter-form button[type="submit"]')->click();
+    wait_until sub { $driver->get_current_url =~ qr/result=complete/ }, 'form 
submitted with meta-result';
+    like $driver->get_current_url, qr/result=complete/, 'URL contains 
meta-result parameter';
+};
+
+subtest 'meta-checkbox updates individual checkboxes' => sub {
+    $driver->get('/tests/overview');
+    $driver->find_element('#filter-panel .card-header')->click();
+    wait_for_element(selector => '#filter-ok', is_displayed => 1);
+    my $ok_cb = $driver->find_element_by_id('filter-ok');
+    my $passed_cb = $driver->find_element_by_id('filter-passed');
+    my $softfailed_cb = $driver->find_element_by_id('filter-softfailed');
+    ok !$passed_cb->is_selected, 'passed checkbox initially unchecked';
+    ok !$softfailed_cb->is_selected, 'softfailed checkbox initially unchecked';
+    $ok_cb->click();
+    ok $passed_cb->is_selected, 'passed checkbox checked after meta-ok click';
+    ok $softfailed_cb->is_selected, 'softfailed checkbox checked after meta-ok 
click';
+    $ok_cb->click();
+    ok !$passed_cb->is_selected, 'passed checkbox unchecked after meta-ok 
click again';
+    ok !$softfailed_cb->is_selected, 'softfailed checkbox unchecked after 
meta-ok click again';
+};
+
+subtest 'redundant parameters are removed' => sub {
+    $driver->get('/tests/overview');
+    $driver->find_element('#filter-panel .card-header')->click();
+    wait_for_element(selector => '#filter-ok', is_displayed => 1);
+    $driver->find_element_by_id('filter-ok')->click();
+    my $passed_cb = $driver->find_element_by_id('filter-passed');
+    ok $passed_cb->is_selected, 'passed selected by meta-ok';
+    $passed_cb->click();
+    $passed_cb->click();
+    $driver->find_element('#filter-form button[type="submit"]')->click();
+    wait_until sub { $driver->get_current_url =~ qr/result=ok/ }, 'form 
submitted';
+    my $url = $driver->get_current_url;
+    like $url, qr/result=ok/, 'URL contains result=ok';
+    unlike $url, qr/result=passed/, 'URL does not contain redundant 
result=passed';
+};
+
+subtest 'all but one results in negative filter' => sub {
+    $driver->get('/tests/overview');
+    $driver->find_element('#filter-panel .card-header')->click();
+    wait_for_element(selector => '#filter-results', is_displayed => 1);
+    my $results_div = $driver->find_element('#filter-results');
+    $driver->find_child_element($results_div, '.filter-bulk-master')->click();
+    $driver->find_element_by_id('filter-passed')->click();
+    $driver->find_element('#filter-form button[type="submit"]')->click();
+    wait_until sub { $driver->get_current_url =~ qr/result__not=passed/ }, 
'form submitted';
+    like $driver->get_current_url, qr/result__not=passed/, 'URL contains 
result__not=passed';
+};
+
+subtest 'meta-checkboxes are ignored by bulk operations' => sub {
+    $driver->get('/tests/overview');
+    $driver->find_element('#filter-panel .card-header')->click();
+    wait_for_element(selector => '#filter-ok', is_displayed => 1);
+    my $results_div = $driver->find_element('#filter-results');
+    my $master = $driver->find_child_element($results_div, 
'.filter-bulk-master');
+    my $ok_cb = $driver->find_element_by_id('filter-ok');
+    ok !$ok_cb->is_selected, 'meta-ok initially unchecked';
+    $master->click();
+    ok $driver->find_element_by_id('filter-passed')->is_selected, 'passed 
selected by master';
+    ok !$ok_cb->is_selected, 'meta-ok NOT selected by master';
+    $driver->find_child_element($results_div, '.filter-bulk-invert')->click();
+    ok !$driver->find_element_by_id('filter-passed')->is_selected, 'passed 
deselected by invert';
+    ok !$ok_cb->is_selected, 'meta-ok still NOT selected by invert';
+};
+
 kill_driver();
 
 done_testing();
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openQA-5.1771473096.98530511/t/ui/18-tests-details.t 
new/openQA-5.1771589939.8f8502b4/t/ui/18-tests-details.t
--- old/openQA-5.1771473096.98530511/t/ui/18-tests-details.t    2026-02-19 
04:51:36.000000000 +0100
+++ new/openQA-5.1771589939.8f8502b4/t/ui/18-tests-details.t    2026-02-20 
13:18:59.000000000 +0100
@@ -545,15 +545,15 @@
     like $driver->find_element('.embedded-logfile')->get_text, 
qr{/usr/bin/qemu-kvm}, 'qemu-kvm is shown in log viewer';
 
     $driver->find_element('#filter-log-file')->send_keys('kate');
-    like $driver->find_element('#filter-info')->get_text, qr{Showing 3 / 1292 
lines},
-      'Showing filter result info for substring';
+    wait_until(sub { $driver->find_element('#filter-info')->get_text =~ 
qr{Showing 3 / 1292 lines} },
+        'Showing filter result info for substring');
     unlike $driver->find_element('.embedded-logfile')->get_text, 
qr{/usr/bin/qemu-kvm},
       'qemu-kvm is not shown when filtering for something else';
     $driver->find_element('#filter-log-file')->clear;
-    like $driver->find_element('#filter-info')->get_text, qr{^$}, 'Filter 
result info cleared';
+    wait_until(sub { $driver->find_element('#filter-info')->get_text eq '' }, 
'Filter result info cleared');
     $driver->find_element('#filter-log-file')->send_keys('/kate-[12]/');
-    like $driver->find_element('#filter-info')->get_text, qr{Showing 2 / 1292 
lines},
-      'Showing filter result info for regex';
+    wait_until(sub { $driver->find_element('#filter-info')->get_text =~ 
qr{Showing 2 / 1292 lines} },
+        'Showing filter result info for regex');
 
     my $url = Mojo::URL->new($driver->execute_script('return 
document.location.toString()'));
     is $url->query->param('filename'), 'autoinst-log.txt', 'URL still contains 
filename after filtering';
@@ -770,8 +770,13 @@
         selector => '#needlediff_selector .show-needle-info',
         is_displayed => 1,
         trigger_function => sub () {
-            # open the candidates menu at the beginning and try again before 
every second check
-            return if $clicks != 0 && ($clicks % 2) == 1;
+            # open the candidates menu at the beginning and try clicking again 
after 50 checks (so after around 5 s)
+            # note: Opening the menu is retried because it is not working 
reliably (see poo#164745). Trying to open
+            #       after every 2nd attempt (as introduced in a134be8) is also 
not reliable as the 2nd click might
+            #       accidentally close the menu again if it shows up after all 
(see poo#196829). So we now give the
+            #       menu around 5 seconds to show up. If it hasn't shown up 
then, it is most likely also not going to
+            #       show up anymore and we can try clicking again.
+            return if $clicks != 0 && ($clicks % 50) == 0;
             wait_for_element(selector => '#candidatesMenu', is_displayed => 
1)->click;
             ++$clicks;
         })->click;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openQA-5.1771473096.98530511/t/ui/21-admin-needles.t 
new/openQA-5.1771589939.8f8502b4/t/ui/21-admin-needles.t
--- old/openQA-5.1771473096.98530511/t/ui/21-admin-needles.t    2026-02-19 
04:51:36.000000000 +0100
+++ new/openQA-5.1771589939.8f8502b4/t/ui/21-admin-needles.t    2026-02-20 
13:18:59.000000000 +0100
@@ -134,7 +134,10 @@
     wait_until(
         sub {
             @outstanding_needles = 
$driver->find_elements('#outstanding-needles li', 'css');
-            return scalar @outstanding_needles == 2;
+            return
+                 scalar @outstanding_needles == 2
+              && $outstanding_needles[0]->get_text() eq 
'inst-timezone-text.json'
+              && $outstanding_needles[1]->get_text() eq 'never-matched.json';
         },
         'still two needle outstanding for deletion'
     );
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openQA-5.1771473096.98530511/t/ui/26-jobs_restart.t 
new/openQA-5.1771589939.8f8502b4/t/ui/26-jobs_restart.t
--- old/openQA-5.1771473096.98530511/t/ui/26-jobs_restart.t     2026-02-19 
04:51:36.000000000 +0100
+++ new/openQA-5.1771589939.8f8502b4/t/ui/26-jobs_restart.t     2026-02-20 
13:18:59.000000000 +0100
@@ -102,8 +102,7 @@
         $driver->find_element('#restart-result-skip-ok-children')
           ->attribute_like('href', qr/skip_ok_result_children=1/, 'skip OK 
children API URL correct');
         $driver->find_element('#restart-result-skip-children')->click;
-        wait_for_ajax(msg => 'wait for redirection to clone job');
-        like $driver->get_current_url, qr{/tests/99982}, 'shows cloned job';
+        wait_until(sub { $driver->get_current_url =~ qr{/tests/99982} }, 
'shows cloned job');
         $jobs->find(99982)->delete;
     };
     subtest 'child job shows options for advanced restart' => sub {
@@ -159,9 +158,8 @@
     subtest 'successful restart' => sub {
         is($driver->get('/tests/99946'), 1, 'go to job 99946');
         update_last_job_id;
-        $driver->find_element('#restart-result')->click();
-        wait_for_ajax(msg => 'successful restart from info panel in test 
results');
-        like($driver->get_current_url(), expected_job_id_regex, 'auto refresh 
to restarted job');
+        $driver->find_element('#restart-result')->click;
+        wait_until(sub { $driver->get_current_url =~ expected_job_id_regex }, 
'auto refresh to restarted job');
         like($driver->find_element('#info_box .card-header')->get_text(),
             qr/textmode\@32bit/, 'restarted job is correct');
     };
@@ -182,8 +180,7 @@
         );
         is($td->get_text(), 'kde@64bit-uefi', 'job not marked as restarted');
         $driver->find_element('#flash-messages-finished-jobs 
button.force-restart')->click();
-        wait_for_ajax(msg => 'forced job restart');
-        is($td->get_text(), 'kde@64bit-uefi (restarted)', 'job is marked as 
restarted');
+        wait_until(sub { $td->get_text() =~ qr/kde\@64bit-uefi \(restarted\)/ 
}, 'job is marked as restarted');
         $_->click for $driver->find_elements('#flash-messages-finished-jobs 
button.close');
 
     };
@@ -192,8 +189,7 @@
         my $td = $driver->find_element('#job_99926 td.test');
         is($td->get_text(), 'minimalx@32bit', '99926 is minimalx@32bit');
         $driver->find_child_element($td, '.restart', 'css')->click();
-        wait_for_ajax(msg => 'successful job restart');
-        is($td->get_text(), 'minimalx@32bit (restarted)', 'job is marked as 
restarted');
+        wait_until(sub { $td->get_text() =~ qr/minimalx\@32bit \(restarted\)/ 
}, 'job is marked as restarted');
         like($driver->find_child_element($td, "./a[\@title='new test']", 
'xpath')->get_attribute('href'),
             expected_job_id_regex, 'restart link is correct');
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openQA-5.1771473096.98530511/t/ui/27-plugin_obs_rsync_status_details.t 
new/openQA-5.1771589939.8f8502b4/t/ui/27-plugin_obs_rsync_status_details.t
--- old/openQA-5.1771473096.98530511/t/ui/27-plugin_obs_rsync_status_details.t  
2026-02-19 04:51:36.000000000 +0100
+++ new/openQA-5.1771589939.8f8502b4/t/ui/27-plugin_obs_rsync_status_details.t  
2026-02-20 13:18:59.000000000 +0100
@@ -64,18 +64,23 @@
     if ($proj eq 'Batch1') {
         # click on the various buttons within the table
         $driver->find_element("tr#folder_$ident .obsbuildsupdate")->click;
-        is $driver->find_element("tr#folder_$ident .obsbuilds")->get_text, 
'fake response',
-          'builds update response shown';
+        wait_until(sub { $driver->find_element("tr#folder_$ident 
.obsbuilds")->get_text eq 'fake response' },
+            'builds update response shown');
 
         $driver->find_element("tr#folder_$ident .lastsyncforget")->click;
         $driver->accept_alert;
-        is $driver->find_element("tr#folder_$ident .lastsync")->get_text, 
'fake response', 'forget response shown';
+        wait_until(sub { $driver->find_element("tr#folder_$ident 
.lastsync")->get_text eq 'fake response' },
+            'forget response shown');
 
         $driver->find_element("tr#folder_$ident .dirtystatusupdate")->click;
-        is $driver->find_element("tr#folder_$ident .dirtystatuscol 
.dirtystatus")->get_text, 'fake response',
-          'dirty status update response shown';
+        wait_until(
+            sub {
+                my $text = $driver->find_element("tr#folder_$ident 
.dirtystatuscol .dirtystatus")->get_text;
+                return $text eq 'fake response' || $text =~ qr/dirty on 
\d{4}-\d{2}-\d{2}/;
+            },
+            'dirty status update response shown'
+        );
 
-        my $actual_requests = $driver->execute_script('return 
window.ajaxRequests;');
         my @expected_requests = (
             {method => 'POST', url => 
'/admin/obs_rsync/BatchedProj%7CBatch1/obs_builds_text'},
             {url => '/admin/obs_rsync/BatchedProj%7CBatch1/obs_builds_text'},
@@ -84,6 +89,9 @@
             {method => 'POST', url => 
'/admin/obs_rsync/BatchedProj/dirty_status'},
             {url => '/admin/obs_rsync/BatchedProj/dirty_status'},
         );
+        wait_until(sub { scalar @{$driver->execute_script('return 
window.ajaxRequests;')} == @expected_requests },
+            'all ajax requests recorded');
+        my $actual_requests = $driver->execute_script('return 
window.ajaxRequests;');
         is_deeply $actual_requests, \@expected_requests, 'ajax requests done 
as expected'
           or always_explain $actual_requests;
     }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openQA-5.1771473096.98530511/templates/webapi/admin/job_template/index.html.ep
 
new/openQA-5.1771589939.8f8502b4/templates/webapi/admin/job_template/index.html.ep
--- 
old/openQA-5.1771473096.98530511/templates/webapi/admin/job_template/index.html.ep
  2026-02-19 04:51:36.000000000 +0100
+++ 
new/openQA-5.1771589939.8f8502b4/templates/webapi/admin/job_template/index.html.ep
  2026-02-20 13:18:59.000000000 +0100
@@ -70,7 +70,7 @@
         <h3 id="job-config-templates-heading" style="display: none;">Job 
templates</h3>
         <p>
             A job template is a combination of machine, product and test suite 
settings. These combination are used
-            to produce actual jobs within a certain job group. Checkout
+            to produce actual jobs within a certain job group. Check out
             <a 
href="http://open.qa/docs/#_using_job_templates_to_automate_jobs_creation"; 
target="blank">the documentation</a>
             for more details.
         </p>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openQA-5.1771473096.98530511/templates/webapi/test/live.html.ep 
new/openQA-5.1771589939.8f8502b4/templates/webapi/test/live.html.ep
--- old/openQA-5.1771473096.98530511/templates/webapi/test/live.html.ep 
2026-02-19 04:51:36.000000000 +0100
+++ new/openQA-5.1771589939.8f8502b4/templates/webapi/test/live.html.ep 
2026-02-20 13:18:59.000000000 +0100
@@ -65,7 +65,7 @@
                 <span class="developer-mode-element" 
data-visible-on="ownSession">
                     Change the test behaviour with the controls below.
                 </span>
-                For more information, checkout the <a 
href="https://github.com/os-autoinst/openQA/blob/master/docs/UsersGuide.asciidoc#developer-mode";
 target="blank">documentation</a>.
+                For more information, check out the <a 
href="https://github.com/os-autoinst/openQA/blob/master/docs/UsersGuide.asciidoc#developer-mode";
 target="blank">documentation</a>.
             </p>
             <div class="mb-3 row">
                 <div class="col-sm-5">
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openQA-5.1771473096.98530511/templates/webapi/test/overview.html.ep 
new/openQA-5.1771589939.8f8502b4/templates/webapi/test/overview.html.ep
--- old/openQA-5.1771473096.98530511/templates/webapi/test/overview.html.ep     
2026-02-19 04:51:36.000000000 +0100
+++ new/openQA-5.1771589939.8f8502b4/templates/webapi/test/overview.html.ep     
2026-02-20 13:18:59.000000000 +0100
@@ -6,7 +6,7 @@
 
 % content_for 'ready_function' => begin
   window.overviewParallelChildrenCollapsableResultsSel = '<%= 
$parallel_children_collapsable_results_sel %>';
-  setupOverview();
+  setupOverview({metaMapping: <%== Mojo::JSON::to_json($meta_mapping) %>});
 % end
 
 % if ($limit_exceeded) {
@@ -96,6 +96,10 @@
                     % for my $result (OpenQA::Jobs::Constants::RESULTS) {
                         <label class="form-label"><input value="<%= $result 
%>" name="result" type="checkbox" id="filter-<%= $result %>"> <%= ucfirst 
$result =~ s/_/ /r %></label>
                     % }
+                    <hr class="my-1">
+                    % for my $result (OpenQA::Jobs::Constants::META_RESULTS) {
+                        <label class="form-label" title="Meta-category: <%= 
$result %>"><input value="<%= $result %>" name="result" type="checkbox" 
id="filter-<%= $result %>" class="filter-meta"> <strong><%= ucfirst $result =~ 
s/_/ /r %></strong></label>
+                    % }
                 </div>
                 <div class="mb-3" id="filter-states">
                     <div class="d-flex align-items-center mb-1">
@@ -108,6 +112,10 @@
                     % for my $state (OpenQA::Jobs::Constants::STATES) {
                         <label class="form-label"><input value="<%= $state %>" 
name="state" type="checkbox" id="filter-<%= $state %>"> <%= ucfirst $state =~ 
s/_/ /r %></label>
                     % }
+                    <hr class="my-1">
+                    % for my $state (OpenQA::Jobs::Constants::META_STATES) {
+                        <label class="form-label" title="Meta-category: <%= 
$state %>"><input value="<%= $state %>" name="state" type="checkbox" 
id="filter-<%= $state %>" class="filter-meta"> <strong><%= ucfirst $state =~ 
s/_/ /r %></strong></label>
+                    % }
                 </div>
                 <div class="row" id="filter-arch-flavor">
                     <div class="col-5">
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openQA-5.1771473096.98530511/tools/unstable_tests.txt 
new/openQA-5.1771589939.8f8502b4/tools/unstable_tests.txt
--- old/openQA-5.1771473096.98530511/tools/unstable_tests.txt   2026-02-19 
04:51:36.000000000 +0100
+++ new/openQA-5.1771589939.8f8502b4/tools/unstable_tests.txt   2026-02-20 
13:18:59.000000000 +0100
@@ -1,4 +1,3 @@
 t/25-cache-service.t
-t/43-scheduling-and-worker-scalability.t
 t/ui/26-jobs_restart.t
 t/ui/13-admin.t

++++++ openQA.obsinfo ++++++
--- /var/tmp/diff_new_pack.9RcvFQ/_old  2026-02-21 21:04:53.640108751 +0100
+++ /var/tmp/diff_new_pack.9RcvFQ/_new  2026-02-21 21:04:53.672110069 +0100
@@ -1,5 +1,5 @@
 name: openQA
-version: 5.1771473096.98530511
-mtime: 1771473096
-commit: 98530511b4f5bb2ebda615f152d1dfd92e468ceb
+version: 5.1771589939.8f8502b4
+mtime: 1771589939
+commit: 8f8502b43e06c431ef8c94e26c0160235e4236cd
 

Reply via email to