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-03-31 15:29:00
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/openQA (Old)
 and      /work/SRC/openSUSE:Factory/.openQA.new.1999 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "openQA"

Tue Mar 31 15:29:00 2026 rev:831 rq:1343779 version:5.1774895777.6c2911d1

Changes:
--------
--- /work/SRC/openSUSE:Factory/openQA/openQA.changes    2026-03-30 
18:36:08.075187303 +0200
+++ /work/SRC/openSUSE:Factory/.openQA.new.1999/openQA.changes  2026-03-31 
15:29:02.905172892 +0200
@@ -1,0 +2,17 @@
+Mon Mar 30 20:17:41 UTC 2026 - [email protected]
+
+- Update to version 5.1774895777.6c2911d1:
+  * feat: Customizable time_limit_days
+  * fix: arrow navigation not working in Chrome-based browsers
+  * style: Remove various magic numbers
+  * fix: ensure cache sync creates parent directory
+  * feat: Improve log message when sending command to ws server fails
+  * refactor: Use `any` instead of `grep` in worker schema
+  * refactor: Avoid repeated access to `$args{command}` in worker schema
+  * fix(clone-job): Restore authorized asset downloads after 06bc5193d25b
+  * fix: restore broken label and flag icons in comments
+  * feat: support parallel Perl tests with PROVE_JOBS in Makefile
+  * fix(ui): Prevent build tag labels from rendering in all caps
+  * feat: replace Test::Strict with Test::Compile in compilation check
+
+-------------------------------------------------------------------

Old:
----
  openQA-5.1774854217.24dbd811.obscpio

New:
----
  openQA-5.1774895777.6c2911d1.obscpio

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

Other differences:
------------------
++++++ openQA-client-test.spec ++++++
--- /var/tmp/diff_new_pack.FLRthc/_old  2026-03-31 15:29:06.221311013 +0200
+++ /var/tmp/diff_new_pack.FLRthc/_new  2026-03-31 15:29:06.249312179 +0200
@@ -18,7 +18,7 @@
 
 %define         short_name openQA-client
 Name:           %{short_name}-test
-Version:        5.1774854217.24dbd811
+Version:        5.1774895777.6c2911d1
 Release:        0
 Summary:        Test package for %{short_name}
 License:        GPL-2.0-or-later

++++++ openQA-devel-test.spec ++++++
--- /var/tmp/diff_new_pack.FLRthc/_old  2026-03-31 15:29:06.533324008 +0200
+++ /var/tmp/diff_new_pack.FLRthc/_new  2026-03-31 15:29:06.541324342 +0200
@@ -18,7 +18,7 @@
 
 %define         short_name openQA-devel
 Name:           %{short_name}-test
-Version:        5.1774854217.24dbd811
+Version:        5.1774895777.6c2911d1
 Release:        0
 Summary:        Test package for %{short_name}
 License:        GPL-2.0-or-later

++++++ openQA-test.spec ++++++
--- /var/tmp/diff_new_pack.FLRthc/_old  2026-03-31 15:29:06.889338837 +0200
+++ /var/tmp/diff_new_pack.FLRthc/_new  2026-03-31 15:29:06.933340669 +0200
@@ -18,7 +18,7 @@
 
 %define         short_name openQA
 Name:           %{short_name}-test
-Version:        5.1774854217.24dbd811
+Version:        5.1774895777.6c2911d1
 Release:        0
 Summary:        Test package for openQA
 License:        GPL-2.0-or-later

++++++ openQA-worker-test.spec ++++++
--- /var/tmp/diff_new_pack.FLRthc/_old  2026-03-31 15:29:07.177350833 +0200
+++ /var/tmp/diff_new_pack.FLRthc/_new  2026-03-31 15:29:07.189351333 +0200
@@ -18,7 +18,7 @@
 
 %define         short_name openQA-worker
 Name:           %{short_name}-test
-Version:        5.1774854217.24dbd811
+Version:        5.1774895777.6c2911d1
 Release:        0
 Summary:        Test package for %{short_name}
 License:        GPL-2.0-or-later

++++++ openQA.spec ++++++
--- /var/tmp/diff_new_pack.FLRthc/_old  2026-03-31 15:29:07.457362496 +0200
+++ /var/tmp/diff_new_pack.FLRthc/_new  2026-03-31 15:29:07.469362996 +0200
@@ -83,7 +83,7 @@
 # Do not require on this in individual sub-packages except for the devel
 # package.
 # The following line is generated from dependencies.yaml
-%define test_requires %common_requires %main_requires %mcp_requires 
%python_scripts_requires %worker_requires curl file jq openssh-common 
os-autoinst perl(App::cpanminus) perl(Selenium::Remote::Driver) >= 1.23 
perl(Selenium::Remote::WDKeys) perl(Test::Exception) perl(Test::Fatal) 
perl(Test::Mock::Time) perl(Test::MockModule) perl(Test::MockObject) 
perl(Test::Mojo) perl(Test::Most) perl(Test::Output) perl(Test::Pod) 
perl(Test::Strict) perl(Test::Warnings) >= 0.029 postgresql-server >= 14 
python3-setuptools
+%define test_requires %common_requires %main_requires %mcp_requires 
%python_scripts_requires %worker_requires curl file jq openssh-common 
os-autoinst perl(App::cpanminus) perl(Selenium::Remote::Driver) >= 1.23 
perl(Selenium::Remote::WDKeys) perl(Test::Compile) perl(Test::Exception) 
perl(Test::Fatal) perl(Test::Mock::Time) perl(Test::MockModule) 
perl(Test::MockObject) perl(Test::Mojo) perl(Test::Most) perl(Test::Output) 
perl(Test::Pod) perl(Test::Warnings) >= 0.029 postgresql-server >= 14 
python3-setuptools
 %ifarch x86_64
 %define qemu qemu qemu-kvm
 %else
@@ -99,7 +99,7 @@
 %define devel_requires %devel_no_selenium_requires chromedriver
 
 Name:           openQA
-Version:        5.1774854217.24dbd811
+Version:        5.1774895777.6c2911d1
 Release:        0
 Summary:        The openQA web-frontend, scheduler and tools
 License:        GPL-2.0-or-later

++++++ openQA-5.1774854217.24dbd811.obscpio -> 
openQA-5.1774895777.6c2911d1.obscpio ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openQA-5.1774854217.24dbd811/Makefile 
new/openQA-5.1774895777.6c2911d1/Makefile
--- old/openQA-5.1774854217.24dbd811/Makefile   2026-03-30 09:03:37.000000000 
+0200
+++ new/openQA-5.1774895777.6c2911d1/Makefile   2026-03-30 20:36:17.000000000 
+0200
@@ -18,6 +18,9 @@
 EXTRA_PROVE_ARGS ?=
 # PROVE: Test application for Perl tests
 PROVE ?= prove
+# Number of parallel jobs for prove
+PROVE_JOBS ?= $(shell nproc 2>/dev/null || echo 1)
+PROVE_JOBS_ARGS ?= -j$(PROVE_JOBS)
 ifeq ($(TESTS),)
 PROVE_ARGS ?= --trap -r ${EXTRA_PROVE_ARGS} t
 else
@@ -280,7 +283,7 @@
        export GLOBIGNORE="$(GLOBIGNORE)";\
        export DEVEL_COVER_DB_FORMAT=JSON;\
        export PERL5OPT="$(COVEROPT)$(PERL5OPT) -It/lib -I$(PWD)/t/lib 
-I$(PWD)/external/os-autoinst-common/lib $(CHECK_GIT_STATUS_OPT) 
-MOpenQA::Test::PatchDeparse";\
-       RETRY=${RETRY} HEAVY=${HEAVY} FULLSTACK=${FULLSTACK} 
HOOK=./tools/delete-coverdb-folder timeout --foreground -s SIGINT -k 5 -v 
${TIMEOUT_RETRIES} tools/retry "${PROVE}" ${PROVE_LIB_ARGS} ${PROVE_ARGS}
+       RETRY=${RETRY} HEAVY=${HEAVY} FULLSTACK=${FULLSTACK} 
HOOK=./tools/delete-coverdb-folder timeout --foreground -s SIGINT -k 5 -v 
${TIMEOUT_RETRIES} tools/retry "${PROVE}" ${PROVE_LIB_ARGS} $(PROVE_JOBS_ARGS) 
${PROVE_ARGS}
 
 .PHONY: setup-database
 setup-database: ## Set up the test database
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openQA-5.1774854217.24dbd811/assets/javascripts/keyevent.js 
new/openQA-5.1774895777.6c2911d1/assets/javascripts/keyevent.js
--- old/openQA-5.1774854217.24dbd811/assets/javascripts/keyevent.js     
2026-03-30 09:03:37.000000000 +0200
+++ new/openQA-5.1774895777.6c2911d1/assets/javascripts/keyevent.js     
2026-03-30 20:36:17.000000000 +0200
@@ -2,8 +2,8 @@
 
 // FIXME: key events may be different in other browsers:
 // http://www.javascripter.net/faq/keyeventconstantsfirefox.htm
-if (typeof KeyEvent === 'undefined') {
-  const KeyEvent = {
+if (typeof KeyEvent === 'undefined' || typeof KeyEvent.DOM_VK_LEFT === 
'undefined') {
+  const keyEventDefaults = {
     DOM_VK_CANCEL: 3,
     DOM_VK_HELP: 6,
     DOM_VK_BACK_SPACE: 8,
@@ -120,4 +120,9 @@
     DOM_VK_QUOTE: 222,
     DOM_VK_META: 224
   };
+  if (typeof KeyEvent === 'undefined') {
+    KeyEvent = keyEventDefaults;
+  } else {
+    Object.assign(KeyEvent, keyEventDefaults);
+  }
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openQA-5.1774854217.24dbd811/assets/javascripts/test_result.js 
new/openQA-5.1774895777.6c2911d1/assets/javascripts/test_result.js
--- old/openQA-5.1774854217.24dbd811/assets/javascripts/test_result.js  
2026-03-30 09:03:37.000000000 +0200
+++ new/openQA-5.1774895777.6c2911d1/assets/javascripts/test_result.js  
2026-03-30 20:36:17.000000000 +0200
@@ -321,32 +321,32 @@
     return;
   }
 
-  switch (e.which) {
-    case KeyEvent.DOM_VK_LEFT:
+  switch (e.key) {
+    case 'ArrowLeft':
       if (!e.shiftKey) {
         prevPreview();
         e.preventDefault();
       }
       break;
-    case KeyEvent.DOM_VK_RIGHT:
+    case 'ArrowRight':
       if (!e.shiftKey) {
         nextPreview();
         e.preventDefault();
       }
       break;
-    case KeyEvent.DOM_VK_ESCAPE:
+    case 'Escape':
       if (!e.shiftKey) {
         setCurrentPreview(null);
         e.preventDefault();
       }
       break;
-    case KeyEvent.DOM_VK_UP:
+    case 'ArrowUp':
       if (e.shiftKey) {
         prevNeedle();
         e.preventDefault();
       }
       break;
-    case KeyEvent.DOM_VK_DOWN:
+    case 'ArrowDown':
       if (e.shiftKey) {
         nextNeedle();
         e.preventDefault();
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openQA-5.1774854217.24dbd811/assets/stylesheets/comments.scss 
new/openQA-5.1774895777.6c2911d1/assets/stylesheets/comments.scss
--- old/openQA-5.1774854217.24dbd811/assets/stylesheets/comments.scss   
2026-03-30 09:03:37.000000000 +0200
+++ new/openQA-5.1774895777.6c2911d1/assets/stylesheets/comments.scss   
2026-03-30 20:36:17.000000000 +0200
@@ -68,7 +68,7 @@
     font-style: normal;
     font-variant: normal;
     text-rendering: auto;
-    font-family: ForkAwesome;
+    font-family: 'Font Awesome 6 Free';
     font-weight: 900;
     font-size: 0.8em;
     position: absolute;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openQA-5.1774854217.24dbd811/cpanfile 
new/openQA-5.1774895777.6c2911d1/cpanfile
--- old/openQA-5.1774854217.24dbd811/cpanfile   2026-03-30 09:03:37.000000000 
+0200
+++ new/openQA-5.1774895777.6c2911d1/cpanfile   2026-03-30 20:36:17.000000000 
+0200
@@ -101,6 +101,7 @@
     requires 'App::cpanminus';
     requires 'Selenium::Remote::Driver', '>= 1.23';
     requires 'Selenium::Remote::WDKeys';
+    requires 'Test::Compile';
     requires 'Test::Exception';
     requires 'Test::Fatal';
     requires 'Test::Mock::Time';
@@ -110,7 +111,6 @@
     requires 'Test::Most';
     requires 'Test::Output';
     requires 'Test::Pod';
-    requires 'Test::Strict';
     requires 'Test::Warnings', '>= 0.029';
 
 };
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openQA-5.1774854217.24dbd811/dependencies.yaml 
new/openQA-5.1774895777.6c2911d1/dependencies.yaml
--- old/openQA-5.1774854217.24dbd811/dependencies.yaml  2026-03-30 
09:03:37.000000000 +0200
+++ new/openQA-5.1774895777.6c2911d1/dependencies.yaml  2026-03-30 
20:36:17.000000000 +0200
@@ -201,7 +201,7 @@
   perl(Test::Exception):
   perl(Test::Mojo):
   perl(Test::Most):
-  perl(Test::Strict):
+  perl(Test::Compile):
   perl(Test::Fatal):
   perl(Test::MockModule):
   perl(Test::MockObject):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openQA-5.1774854217.24dbd811/dist/rpm/openQA.spec 
new/openQA-5.1774895777.6c2911d1/dist/rpm/openQA.spec
--- old/openQA-5.1774854217.24dbd811/dist/rpm/openQA.spec       2026-03-30 
09:03:37.000000000 +0200
+++ new/openQA-5.1774895777.6c2911d1/dist/rpm/openQA.spec       2026-03-30 
20:36:17.000000000 +0200
@@ -83,7 +83,7 @@
 # Do not require on this in individual sub-packages except for the devel
 # package.
 # The following line is generated from dependencies.yaml
-%define test_requires %common_requires %main_requires %mcp_requires 
%python_scripts_requires %worker_requires curl file jq openssh-common 
os-autoinst perl(App::cpanminus) perl(Selenium::Remote::Driver) >= 1.23 
perl(Selenium::Remote::WDKeys) perl(Test::Exception) perl(Test::Fatal) 
perl(Test::Mock::Time) perl(Test::MockModule) perl(Test::MockObject) 
perl(Test::Mojo) perl(Test::Most) perl(Test::Output) perl(Test::Pod) 
perl(Test::Strict) perl(Test::Warnings) >= 0.029 postgresql-server >= 14 
python3-setuptools
+%define test_requires %common_requires %main_requires %mcp_requires 
%python_scripts_requires %worker_requires curl file jq openssh-common 
os-autoinst perl(App::cpanminus) perl(Selenium::Remote::Driver) >= 1.23 
perl(Selenium::Remote::WDKeys) perl(Test::Compile) perl(Test::Exception) 
perl(Test::Fatal) perl(Test::Mock::Time) perl(Test::MockModule) 
perl(Test::MockObject) perl(Test::Mojo) perl(Test::Most) perl(Test::Output) 
perl(Test::Pod) perl(Test::Warnings) >= 0.029 postgresql-server >= 14 
python3-setuptools
 %ifarch x86_64
 %define qemu qemu qemu-kvm
 %else
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openQA-5.1774854217.24dbd811/etc/openqa/openqa.ini 
new/openQA-5.1774895777.6c2911d1/etc/openqa/openqa.ini
--- old/openQA-5.1774854217.24dbd811/etc/openqa/openqa.ini      2026-03-30 
09:03:37.000000000 +0200
+++ new/openQA-5.1774895777.6c2911d1/etc/openqa/openqa.ini      2026-03-30 
20:36:17.000000000 +0200
@@ -128,6 +128,9 @@
 ## How many builds to show per job group on the web UI front page
 ## Can be overridden with the limit_builds query param
 #frontpage_builds = 3
+## Maximum age for the builds per job group on the web UI front page
+## Can be overridden with the time_limit_days query param
+#frontpage_time_limit_days = 14
 
 ## List of hosts (space-separated) where scenario definitions specified via
 ## `SCENARIO_DEFINITIONS_YAML_FILE=https://…` are allowed to be downloaded from
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openQA-5.1774854217.24dbd811/lib/OpenQA/Assets.pm 
new/openQA-5.1774895777.6c2911d1/lib/OpenQA/Assets.pm
--- old/openQA-5.1774854217.24dbd811/lib/OpenQA/Assets.pm       2026-03-30 
09:03:37.000000000 +0200
+++ new/openQA-5.1774895777.6c2911d1/lib/OpenQA/Assets.pm       2026-03-30 
20:36:17.000000000 +0200
@@ -13,12 +13,14 @@
 use YAML::PP qw(LoadFile);
 use Feature::Compat::Try;
 
+use constant ASSET_PACK_VERSION_NO_RETRY => 2.13;
+
 sub setup ($server) {
     # setup asset pack, note that the config file is shared with 
tools/generate-packed-assets
     $server->plugin(AssetPack => LoadFile($server->home->child('assets', 
'assetpack.yml')));
 
     # The feature was added in the 2.14 release, the version check can be 
removed once openQA depends on a newer version
-    $server->asset->store->retries(5) if 
$Mojolicious::Plugin::AssetPack::VERSION > 2.13;
+    $server->asset->store->retries(5) if 
$Mojolicious::Plugin::AssetPack::VERSION > ASSET_PACK_VERSION_NO_RETRY;
 
     # -> read assets/assetpack.def
     local $SIG{CHLD};
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openQA-5.1774854217.24dbd811/lib/OpenQA/BuildResults.pm 
new/openQA-5.1774895777.6c2911d1/lib/OpenQA/BuildResults.pm
--- old/openQA-5.1774854217.24dbd811/lib/OpenQA/BuildResults.pm 2026-03-30 
09:03:37.000000000 +0200
+++ new/openQA-5.1774895777.6c2911d1/lib/OpenQA/BuildResults.pm 2026-03-30 
20:36:17.000000000 +0200
@@ -14,6 +14,8 @@
 use Sort::Versions;
 use Time::Seconds;
 
+use constant DEFAULT_BUILD_RESULTS_LIMIT => 400;
+
 sub init_job_figures ($job_result) {
     # relevant distributions for the build (hash is used as a set)
     $job_result->{distris} = {};
@@ -123,7 +125,7 @@
     my $sort_column = $buildver_sort_mode == BUILD_SORT_BY_OLDEST_JOB ? 
'oldest_job' : 'newest_job';
 
     # 400 is the max. limit selectable in the group overview
-    my $row_limit = (defined($limit) && $limit > 400) ? $limit : 400;
+    my $row_limit = (defined($limit) && $limit > DEFAULT_BUILD_RESULTS_LIMIT) 
? $limit : DEFAULT_BUILD_RESULTS_LIMIT;
     my @search_cols = qw(VERSION BUILD);
     my %search_opts = (
         select => [@search_cols, {max => 'id', -as => 'newest_job'}, {min => 
'id', -as => 'oldest_job'}],
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openQA-5.1774854217.24dbd811/lib/OpenQA/CacheService/Response.pm 
new/openQA-5.1774895777.6c2911d1/lib/OpenQA/CacheService/Response.pm
--- old/openQA-5.1774854217.24dbd811/lib/OpenQA/CacheService/Response.pm        
2026-03-30 09:03:37.000000000 +0200
+++ new/openQA-5.1774895777.6c2911d1/lib/OpenQA/CacheService/Response.pm        
2026-03-30 20:36:17.000000000 +0200
@@ -4,6 +4,8 @@
 package OpenQA::CacheService::Response;
 use Mojo::Base -base, -signatures;
 
+use constant MAX_INACTIVE_JOBS_OFFSET => 40;
+
 has [qw(data error)];
 
 # define soft-limit for inactive Minion jobs (enforced when determining idle 
worker slots availability)
@@ -11,7 +13,7 @@
 
 # define hard-limit for inactive Minion jobs (enforced on setup of already 
started openQA job)
 has max_inactive_jobs_hard_limit => sub ($self) {
-    $ENV{OPENQA_CACHE_MAX_INACTIVE_JOBS_HARD_LIMIT} // 
($self->max_inactive_jobs + 40);
+    $ENV{OPENQA_CACHE_MAX_INACTIVE_JOBS_HARD_LIMIT} // 
($self->max_inactive_jobs + MAX_INACTIVE_JOBS_OFFSET);
 };
 
 sub has_error ($self) { !!$self->error }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openQA-5.1774854217.24dbd811/lib/OpenQA/CacheService/Task/Sync.pm 
new/openQA-5.1774895777.6c2911d1/lib/OpenQA/CacheService/Task/Sync.pm
--- old/openQA-5.1774854217.24dbd811/lib/OpenQA/CacheService/Task/Sync.pm       
2026-03-30 09:03:37.000000000 +0200
+++ new/openQA-5.1774895777.6c2911d1/lib/OpenQA/CacheService/Task/Sync.pm       
2026-03-30 20:36:17.000000000 +0200
@@ -4,6 +4,7 @@
 package OpenQA::CacheService::Task::Sync;
 use Mojo::Base 'Mojolicious::Plugin', -signatures;
 use OpenQA::Task::SignalGuard;
+use Mojo::File 'path';
 
 use Mojo::URL;
 use Time::Seconds;
@@ -35,6 +36,7 @@
     my $ctx = $app->log->context("[#$job_id]");
     $ctx->info(qq{Sync: "$from" to "$to"});
 
+    path($to)->make_path;
     my @cmd = (qw(rsync -avHP --timeout), RSYNC_TIMEOUT, "$from/", 
qw(--delete), "$to/tests/");
     my $cmd = join ' ', @cmd;
     my $status;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openQA-5.1774854217.24dbd811/lib/OpenQA/CacheService.pm 
new/openQA-5.1774895777.6c2911d1/lib/OpenQA/CacheService.pm
--- old/openQA-5.1774854217.24dbd811/lib/OpenQA/CacheService.pm 2026-03-30 
09:03:37.000000000 +0200
+++ new/openQA-5.1774895777.6c2911d1/lib/OpenQA/CacheService.pm 2026-03-30 
20:36:17.000000000 +0200
@@ -6,6 +6,7 @@
 
 use Mojo::SQLite;
 use Mojo::File 'path';
+use Time::Seconds;
 use OpenQA::Worker::Settings;
 use OpenQA::CacheService::Model::Cache;
 use OpenQA::CacheService::Model::Downloads;
@@ -125,7 +126,7 @@
 
     local $ENV{MOJO_LOG_SHORT} = 1;
     my $app = __PACKAGE__->new;
-    $ENV{MOJO_INACTIVITY_TIMEOUT} //= 300;
+    $ENV{MOJO_INACTIVITY_TIMEOUT} //= ONE_MINUTE * 5;
     $app->log->debug("Starting cache service: $0 @args");
     $app->defaults->{service_pid} = $$;
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openQA-5.1774854217.24dbd811/lib/OpenQA/Client/Archive.pm 
new/openQA-5.1774895777.6c2911d1/lib/OpenQA/Client/Archive.pm
--- old/openQA-5.1774854217.24dbd811/lib/OpenQA/Client/Archive.pm       
2026-03-30 09:03:37.000000000 +0200
+++ new/openQA-5.1774895777.6c2911d1/lib/OpenQA/Client/Archive.pm       
2026-03-30 20:36:17.000000000 +0200
@@ -10,6 +10,8 @@
 use Mojo::JSON 'encode_json';
 use HTTP::Status qw(:constants);
 
+use constant DEFAULT_MAX_ASSET_SIZE => 1024 * 1024 * 200;
+
 sub run ($self, $options) {
     croak 'Options must be a HASH ref' unless ref $options eq 'HASH';
     croak 'Need a URL to download job information' unless $options->{url};
@@ -17,8 +19,7 @@
     my $url = Mojo::URL->new($options->{url});
     my $req = $self->client->get($url);
     my $res = $req->res;
-    my $default_max_asset_size = 1024 * 1024 * 200;
-    $options->{'asset-size-limit'} //= $default_max_asset_size;
+    $options->{'asset-size-limit'} //= DEFAULT_MAX_ASSET_SIZE;
     $self->client->max_response_size($options->{'asset-size-limit'});
 
     my $code = $res->code;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openQA-5.1774854217.24dbd811/lib/OpenQA/Client/Upload.pm 
new/openQA-5.1774895777.6c2911d1/lib/OpenQA/Client/Upload.pm
--- old/openQA-5.1774854217.24dbd811/lib/OpenQA/Client/Upload.pm        
2026-03-30 09:03:37.000000000 +0200
+++ new/openQA-5.1774895777.6c2911d1/lib/OpenQA/Client/Upload.pm        
2026-03-30 20:36:17.000000000 +0200
@@ -10,6 +10,8 @@
 use Mojo::File qw(path);
 use Feature::Compat::Try;
 
+use constant DEFAULT_CHUNK_SIZE => 1_000_000;
+
 sub _upload_asset_fail ($self, $uri, $form) {
     $form->{state} = 'fail';
     return $self->client->start($self->_build_post("$uri/upload_state" => 
$form));
@@ -38,7 +40,7 @@
         return undef;
     }
 
-    my $chunk_size = $opts->{chunk_size} // 1000000;
+    my $chunk_size = $opts->{chunk_size} // DEFAULT_CHUNK_SIZE;
     my $parts = OpenQA::File->new(file => 
Mojo::File->new($opts->{file}))->split($chunk_size);
     $self->emit('upload_chunk.prepare', $parts);
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openQA-5.1774854217.24dbd811/lib/OpenQA/Command.pm 
new/openQA-5.1774895777.6c2911d1/lib/OpenQA/Command.pm
--- old/openQA-5.1774854217.24dbd811/lib/OpenQA/Command.pm      2026-03-30 
09:03:37.000000000 +0200
+++ new/openQA-5.1774895777.6c2911d1/lib/OpenQA/Command.pm      2026-03-30 
20:36:17.000000000 +0200
@@ -13,6 +13,8 @@
 use Mojo::Transaction::HTTP;
 use Term::ANSIColor qw(colored);
 
+use constant MOJO_CONNECT_TIMEOUT => $ENV{MOJO_CONNECT_TIMEOUT} // 30;
+
 my $JSON = 
Cpanel::JSON::XS->new->utf8->canonical->allow_nonref->allow_unknown->allow_blessed->convert_blessed
   ->stringify_infnan->escape_slash->allow_dupkeys->pretty;
 my $PARAM_RE = qr/^([[:alnum:]_\[\]\.\:]+)=(.*)$/s;
@@ -118,7 +120,7 @@
 }
 
 sub retry_tx ($self, $client, $tx, $retries = undef, $delay = undef) {
-    $client->connect_timeout($ENV{MOJO_CONNECT_TIMEOUT} // 30);
+    $client->connect_timeout(MOJO_CONNECT_TIMEOUT);
     $delay //= $ENV{OPENQA_CLI_RETRY_SLEEP_TIME_S} // 3;
     $retries //= $ENV{OPENQA_CLI_RETRIES} // 0;
     my $factor = $ENV{OPENQA_CLI_RETRY_FACTOR} // 1;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openQA-5.1774854217.24dbd811/lib/OpenQA/File.pm 
new/openQA-5.1774895777.6c2911d1/lib/OpenQA/File.pm
--- old/openQA-5.1774854217.24dbd811/lib/OpenQA/File.pm 2026-03-30 
09:03:37.000000000 +0200
+++ new/openQA-5.1774895777.6c2911d1/lib/OpenQA/File.pm 2026-03-30 
20:36:17.000000000 +0200
@@ -10,6 +10,8 @@
 use Fcntl 'SEEK_SET';
 use OpenQA::Files;
 
+use constant FILE_CHUNK_SIZE => 10_000_000;
+
 has file => sub { Mojo::File->new };
 has [qw(start end index cksum total content total_cksum)];
 
@@ -74,7 +76,7 @@
 }
 
 sub split ($self, $chunk_size = undef) {
-    $chunk_size //= 10000000;
+    $chunk_size //= FILE_CHUNK_SIZE;
     croak 'You need to define a file' unless defined $self->file();
     $self->file(Mojo::File->new($self->file())) unless ref $self->file eq 
'Mojo::File';
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openQA-5.1774854217.24dbd811/lib/OpenQA/Markdown.pm 
new/openQA-5.1774895777.6c2911d1/lib/OpenQA/Markdown.pm
--- old/openQA-5.1774854217.24dbd811/lib/OpenQA/Markdown.pm     2026-03-30 
09:03:37.000000000 +0200
+++ new/openQA-5.1774895777.6c2911d1/lib/OpenQA/Markdown.pm     2026-03-30 
20:36:17.000000000 +0200
@@ -13,11 +13,13 @@
 
 our @EXPORT_OK = qw(bugref_to_html is_light_color markdown_to_html);
 
+use constant IS_LIGHT_COLOR_THRESHOLD => 380;
+
 sub is_light_color ($color) {
     return undef unless $color =~ 
m/^#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})$/;
     my ($red, $green, $blue) = ($1, $2, $3);
     my $sum = (hex $red) + (hex $green) + (hex $blue);
-    return $sum > 380;
+    return $sum > IS_LIGHT_COLOR_THRESHOLD;
 }
 
 sub bugref_to_html ($bugref, $fancy = 0) {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openQA-5.1774854217.24dbd811/lib/OpenQA/Scheduler.pm 
new/openQA-5.1774895777.6c2911d1/lib/OpenQA/Scheduler.pm
--- old/openQA-5.1774854217.24dbd811/lib/OpenQA/Scheduler.pm    2026-03-30 
09:03:37.000000000 +0200
+++ new/openQA-5.1774895777.6c2911d1/lib/OpenQA/Scheduler.pm    2026-03-30 
20:36:17.000000000 +0200
@@ -4,13 +4,14 @@
 package OpenQA::Scheduler;
 use Mojo::Base 'Mojolicious', -signatures;
 
-use OpenQA::Setup;
 use Mojo::IOLoop;
-use OpenQA::Log qw(log_debug setup_log);
 use Mojo::Server::Daemon;
+use Scalar::Util qw(looks_like_number);
+use Time::Seconds;
+use OpenQA::Log qw(log_debug setup_log);
 use OpenQA::Schema;
 use OpenQA::Scheduler::Model::Jobs;
-use Scalar::Util qw(looks_like_number);
+use OpenQA::Setup;
 
 # Scheduler default clock. Defaults to 20 s
 # Optimization rule of thumb is:
@@ -92,7 +93,7 @@
     $self->plugin('Gru');
 
     # check for stale jobs every 2 minutes
-    Mojo::IOLoop->recurring(120 => \&_check_stale);
+    Mojo::IOLoop->recurring(ONE_MINUTE * 2 => \&_check_stale);
 
     # initial schedule
     Mojo::IOLoop->next_tick(
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openQA-5.1774854217.24dbd811/lib/OpenQA/Schema/Result/Jobs.pm 
new/openQA-5.1774895777.6c2911d1/lib/OpenQA/Schema/Result/Jobs.pm
--- old/openQA-5.1774854217.24dbd811/lib/OpenQA/Schema/Result/Jobs.pm   
2026-03-30 09:03:37.000000000 +0200
+++ new/openQA-5.1774895777.6c2911d1/lib/OpenQA/Schema/Result/Jobs.pm   
2026-03-30 20:36:17.000000000 +0200
@@ -50,6 +50,9 @@
 # job settings which are defined directly as column of the jobs table
 use constant MAIN_SETTINGS => qw(DISTRI VERSION FLAVOR ARCH TEST MACHINE 
BUILD);
 
+use constant MAX_LENGTH_REASON => 300;
+use constant JOB_INVESTIGATE_GIT_TIMEOUT => 20;
+
 __PACKAGE__->table('jobs');
 __PACKAGE__->load_components(qw(InflateColumn::DateTime FilterColumn 
Timestamps));
 __PACKAGE__->add_columns(
@@ -1882,7 +1885,8 @@
 
 sub git_diff ($self, $dir, $refspec_range, $limit = undef) {
     return "Invalid range $refspec_range" if $refspec_range =~ 
m/UNKNOWN|unreadable git hash/;
-    my $timeout = 
OpenQA::App->singleton->config->{global}->{job_investigate_git_timeout} // 20;
+    my $timeout = 
OpenQA::App->singleton->config->{global}->{job_investigate_git_timeout}
+      // JOB_INVESTIGATE_GIT_TIMEOUT;
     my $cmd = ['git', '-C', $dir, 'rev-list', '--count', $refspec_range];
     my $res = run_cmd_with_log_return_error($cmd);
     my $out = $res->{stdout} . $res->{stderr};
@@ -2198,7 +2202,7 @@
         # limit length of the reason
         # note: The reason can be anything the worker picked up as useful 
information so better cut it at a
         # reasonable, human-readable length. This also avoids growing the 
database too big.
-        $reason = substr($reason, 0, 300) . '…' if length $reason > 300;
+        $reason = substr($reason, 0, MAX_LENGTH_REASON) . '…' if length 
$reason > MAX_LENGTH_REASON;
         $reason .= $append_reason;
         $new_val->{reason} = $reason;
     }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openQA-5.1774854217.24dbd811/lib/OpenQA/Schema/Result/ScheduledProducts.pm 
new/openQA-5.1774895777.6c2911d1/lib/OpenQA/Schema/Result/ScheduledProducts.pm
--- 
old/openQA-5.1774854217.24dbd811/lib/OpenQA/Schema/Result/ScheduledProducts.pm  
    2026-03-30 09:03:37.000000000 +0200
+++ 
new/openQA-5.1774895777.6c2911d1/lib/OpenQA/Schema/Result/ScheduledProducts.pm  
    2026-03-30 20:36:17.000000000 +0200
@@ -10,6 +10,7 @@
 use Exporter 'import';
 use File::Basename;
 use Feature::Compat::Try;
+use HTTP::Status qw(:constants);
 use OpenQA::App;
 use OpenQA::Log qw(log_debug log_warning log_error);
 use OpenQA::Utils;
@@ -359,7 +360,7 @@
     else {
         $result = $self->_generate_jobs($args, \@notes, $skip_chained_deps, 
$include_children);
     }
-    return {error => $result->{error_message}, error_code => 
$result->{error_code} // 400}
+    return {error => $result->{error_message}, error_code => 
$result->{error_code} // HTTP_BAD_REQUEST}
       if defined $result->{error_message};
     my $jobs = $result->{settings_result};
     # take some attributes from the first job to guess what old jobs to cancel
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openQA-5.1774854217.24dbd811/lib/OpenQA/Schema/Result/Workers.pm 
new/openQA-5.1774895777.6c2911d1/lib/OpenQA/Schema/Result/Workers.pm
--- old/openQA-5.1774854217.24dbd811/lib/OpenQA/Schema/Result/Workers.pm        
2026-03-30 09:03:37.000000000 +0200
+++ new/openQA-5.1774895777.6c2911d1/lib/OpenQA/Schema/Result/Workers.pm        
2026-03-30 20:36:17.000000000 +0200
@@ -13,8 +13,14 @@
 use OpenQA::Constants qw(WORKER_API_COMMANDS DB_TIMESTAMP_ACCURACY);
 use OpenQA::Jobs::Constants;
 use Mojo::JSON qw(encode_json decode_json);
+use List::Util qw(any);
+use Time::Seconds;
 use DBI qw(:sql_types);
 
+use constant WS_SERVER_GRACE_PERIOD => $ENV{OPENQA_WEB_SOCKETS_GRACE_PERIOD} 
// (ONE_MINUTE * 5);
+
+use constant VNC_PORT_OFFSET => 5990;
+
 __PACKAGE__->table('workers');
 __PACKAGE__->load_components(qw(InflateColumn::DateTime Timestamps));
 __PACKAGE__->add_columns(
@@ -176,30 +182,34 @@
 }
 
 sub send_command ($self, %args) {
-    return undef if (!defined $args{command});
+    return undef unless defined(my $command = $args{command});
 
-    if (!grep { $args{command} eq $_ } WORKER_API_COMMANDS) {
+    if (!any { $command eq $_ } WORKER_API_COMMANDS) {
         my $msg = 'Trying to issue unknown command "%s" for worker "%s:%n"';
-        log_error(sprintf $msg, $args{command}, $self->host, $self->instance);
+        log_error(sprintf $msg, $command, $self->host, $self->instance);
         return undef;
     }
 
     try {
-        OpenQA::App->singleton->emit_event(
-            openqa_command_enqueue => {workerid => $self->id, command => 
$args{command}});
+        OpenQA::App->singleton->emit_event(openqa_command_enqueue => {workerid 
=> $self->id, command => $command});
     }
     catch ($e) { }
 
     # prevent ws server querying itself (which would cause it to hang until 
the connection times out)
     if (OpenQA::WebSockets::Client::is_current_process_the_websocket_server) {
-        return OpenQA::WebSockets::ws_send($self->id, $args{command}, 
$args{job_id}, undef);
+        return OpenQA::WebSockets::ws_send($self->id, $command, $args{job_id}, 
undef);
     }
 
     my $client = OpenQA::WebSockets::Client->singleton;
-    try { $client->send_msg($self->id, $args{command}, $args{job_id}) }
+    state $first_error_time = undef;
+    try { $client->send_msg($self->id, $command, $args{job_id}); 
$first_error_time = undef; }
     catch ($e) {
-        log_error(sprintf 'Failed dispatching message to websocket server over 
ipc for worker "%s:%n": %s',
-            $self->host, $self->instance, $e);
+        my $msg = sprintf 'Failed to send command "%s" to websocket server 
(regarding worker "%s:%n"): %s',
+          $command, $self->host, $self->instance, $e;
+        my $error_time = time;
+        my $within_grace_period = !$first_error_time || ($error_time - 
$first_error_time) <= WS_SERVER_GRACE_PERIOD;
+        $first_error_time //= $error_time;
+        $within_grace_period ? log_warning($msg) : log_error($msg);
         return undef;
     }
     return 1;
@@ -244,7 +254,7 @@
 
 sub vnc_argument ($self) {
     my $hostname = $self->get_property('WORKER_HOSTNAME') || $self->host;
-    my $instance = $self->instance + 5990;
+    my $instance = $self->instance + VNC_PORT_OFFSET;
     return "$hostname:$instance";
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openQA-5.1774854217.24dbd811/lib/OpenQA/Script/CloneJob.pm 
new/openQA-5.1774895777.6c2911d1/lib/OpenQA/Script/CloneJob.pm
--- old/openQA-5.1774854217.24dbd811/lib/OpenQA/Script/CloneJob.pm      
2026-03-30 09:03:37.000000000 +0200
+++ new/openQA-5.1774895777.6c2911d1/lib/OpenQA/Script/CloneJob.pm      
2026-03-30 20:36:17.000000000 +0200
@@ -168,15 +168,32 @@
 
 sub _run_cmd ($command, @args) { system $command, @args; return $? == 0 ? '' : 
_format_cmd_error($command) }
 
-sub mirror ($url_handler, $from, $dst) {
-    my @curl_args = @{$url_handler->{curl_args}};
-    my $secrets = $url_handler->{secrets};
+sub _url_from_cmd ($command, @args) {    # use open (and not qx) to avoid 
splitting arguments or using a shell
+    open my $fh, '-|', $command, @args or return "Failed to execute 
'$command': $!";
+    my $out = do { local $/; <$fh> };
+    close $fh;
+    return $? == 0 ? Mojo::URL->new($out) : _format_cmd_error($command);
+}
+
+sub _args_for_header ($headers, $name) {
+    return (map { ('-H', "$name: $_") } @{$headers->every_header($name)});
+}
+
+sub _auth_args ($from, $secrets) {
     my $headers = Mojo::Headers->new;
     OpenQA::UserAgent::add_auth_headers($headers, $from, @$secrets) if 
$secrets;
-    for my $name (@{$headers->names}) {
-        push @curl_args, '-H', "$name: " . $_ for 
@{$headers->every_header($name)};
-    }
-    _run_cmd CURL, @curl_args, qw(--continue-at - --output), $dst, $from;
+    return [map { _args_for_header $headers, $_ } @{$headers->names}];
+}
+
+sub _resolve_redirection ($from, $curl_args, $secrets) {
+    my @effective_url_args = qw(--silent --follow --head --output /dev/null -w 
%{url_effective});
+    return _url_from_cmd CURL, @$curl_args, @{_auth_args($from, $secrets)}, 
@effective_url_args, $from;
+}
+
+sub mirror ($url_handler, $from, $dst) {
+    my ($curl_args, $secrets) = ($url_handler->{curl_args}, 
$url_handler->{secrets});
+    return $from if ref($from = _resolve_redirection $from, $curl_args, 
$secrets) ne 'Mojo::URL';
+    return _run_cmd CURL, @$curl_args, @{_auth_args($from, $secrets)}, 
qw(--continue-at - --output), $dst, $from;
 }
 
 sub clone_job_download_assets ($jobid, $job, $url_handler, $options) {
@@ -229,7 +246,7 @@
 }
 
 sub make_curl_arguments ($options) {
-    my @args = ('--follow', '--retry', $options->{retry}, 
'--retry-connrefused');
+    my @args = ('--retry', $options->{retry}, '--retry-connrefused');
     push @args, '--no-progress-meter' unless $options->{'show-progress'};
     push @args, '--verbose' if $options->{verbose};
     return \@args;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openQA-5.1774854217.24dbd811/lib/OpenQA/Setup.pm 
new/openQA-5.1774895777.6c2911d1/lib/OpenQA/Setup.pm
--- old/openQA-5.1774854217.24dbd811/lib/OpenQA/Setup.pm        2026-03-30 
09:03:37.000000000 +0200
+++ new/openQA-5.1774895777.6c2911d1/lib/OpenQA/Setup.pm        2026-03-30 
20:36:17.000000000 +0200
@@ -112,6 +112,7 @@
             access_control_allow_origin_header => undef,
             api_hmac_time_tolerance => 300,
             frontpage_builds => 3,
+            frontpage_time_limit_days => 14,
             scenario_definitions_allowed_hosts => 'github.com 
raw.githubusercontent.com',
         },
         rate_limits => {
@@ -476,7 +477,7 @@
     if (my $days = $c->app->config->{global}->{hsts}) {
         $c->res->headers->header(
             'Strict-Transport-Security' => sprintf 'max-age=%d; 
includeSubDomains',
-            $days * 24 * 60 * 60
+            $days * ONE_DAY
         );
     }
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openQA-5.1774854217.24dbd811/lib/OpenQA/Shared/Controller/Auth.pm 
new/openQA-5.1774895777.6c2911d1/lib/OpenQA/Shared/Controller/Auth.pm
--- old/openQA-5.1774854217.24dbd811/lib/OpenQA/Shared/Controller/Auth.pm       
2026-03-30 09:03:37.000000000 +0200
+++ new/openQA-5.1774895777.6c2911d1/lib/OpenQA/Shared/Controller/Auth.pm       
2026-03-30 20:36:17.000000000 +0200
@@ -8,6 +8,7 @@
 use OpenQA::Log qw(log_trace);
 use Mojo::Util qw(hmac_sha1_sum secure_compare);
 use Mojo::URL;
+use Time::Seconds;
 
 sub check ($self) {
     my $config = $self->app->config;
@@ -108,7 +109,7 @@
 sub _is_timestamp_valid ($self, $our_timestamp, $remote_timestamp) {
     my $log = $self->app->log;
     my $tolerance = $self->config->{api_hmac_time_tolerance}
-      // 300;    # make extra sure this value is never empty to avoid security 
issues
+      // ONE_MINUTE * 5;    # make extra sure this value is never empty to 
avoid security issues
 
     return 1 if (abs($our_timestamp - $remote_timestamp) <= $tolerance);
     $log->debug(
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openQA-5.1774854217.24dbd811/lib/OpenQA/Shared/Controller/Running.pm 
new/openQA-5.1774895777.6c2911d1/lib/OpenQA/Shared/Controller/Running.pm
--- old/openQA-5.1774854217.24dbd811/lib/OpenQA/Shared/Controller/Running.pm    
2026-03-30 09:03:37.000000000 +0200
+++ new/openQA-5.1774895777.6c2911d1/lib/OpenQA/Shared/Controller/Running.pm    
2026-03-30 20:36:17.000000000 +0200
@@ -9,16 +9,18 @@
 use Mojo::JSON qw(encode_json decode_json);
 use Feature::Compat::Try;
 use File::stat;
+use HTTP::Status qw(:constants);
+use Time::Seconds;
 use OpenQA::Constants qw(WORKER_COMMAND_LIVELOG_STOP 
WORKER_COMMAND_LIVELOG_START);
 use OpenQA::Log qw(log_debug log_error);
 use OpenQA::Utils;
 use OpenQA::WebSockets::Client;
 use OpenQA::Jobs::Constants;
 use OpenQA::Schema::Result::Jobs;
-use HTTP::Status qw(:constants);
 
 use constant IMAGE_STREAMING_INTERVAL => $ENV{OPENQA_IMAGE_STREAMING_INTERVAL} 
// 0.3;
 use constant TEXT_STREAMING_INTERVAL => $ENV{OPENQA_TEXT_STREAMING_INTERVAL} 
// 1.0;
+use constant STREAMING_TIMEOUT => ONE_MINUTE * 15;
 
 sub init ($self, $page_name = undef) {
     my $job = 
$self->app->schema->resultset('Jobs')->find($self->param('testid'));
@@ -82,7 +84,7 @@
     my $worker = $job->worker;
     my $logfile = $worker->get_property('WORKER_TMPDIR') . "/$file_name";
     $self->render_later;
-    Mojo::IOLoop->stream($self->tx->connection)->timeout(900);
+    Mojo::IOLoop->stream($self->tx->connection)->timeout(STREAMING_TIMEOUT);
     my $res = $self->res;
     $res->code(HTTP_OK);
     $res->headers->content_type('text/event-stream');
@@ -178,10 +180,10 @@
 
     # send images via server-sent events
     $self->render_later;
-    Mojo::IOLoop->stream($self->tx->connection)->timeout(900);
+    Mojo::IOLoop->stream($self->tx->connection)->timeout(STREAMING_TIMEOUT);
     my $res = $self->res;
     my $headers = $res->headers;
-    $res->code(200);
+    $res->code(HTTP_OK);
     $headers->content_type('text/event-stream');
 
     # set CORS headers required when not using a reverse proxy (so the port 
differs)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openQA-5.1774854217.24dbd811/lib/OpenQA/Task/Job/FinalizeResults.pm 
new/openQA-5.1774895777.6c2911d1/lib/OpenQA/Task/Job/FinalizeResults.pm
--- old/openQA-5.1774854217.24dbd811/lib/OpenQA/Task/Job/FinalizeResults.pm     
2026-03-30 09:03:37.000000000 +0200
+++ new/openQA-5.1774895777.6c2911d1/lib/OpenQA/Task/Job/FinalizeResults.pm     
2026-03-30 20:36:17.000000000 +0200
@@ -8,6 +8,9 @@
 use Time::Seconds;
 use Feature::Compat::Try;
 
+use constant DEFAULT_OPENQA_JOB_DONE_HOOK_RETRIES => 53;
+use constant DEFAULT_OPENQA_JOB_DONE_HOOK_SKIP_RC => 142;
+
 sub register ($self, $app, @args) {
     $app->minion->add_task(finalize_job_results => \&_finalize_results);
 }
@@ -51,8 +54,10 @@
     my $settings = $openqa_job->settings_hash;
     my $delay = $settings->{_TRIGGER_JOB_DONE_DELAY} // 
$ENV{OPENQA_JOB_DONE_HOOK_DELAY} // ONE_MINUTE;
     # Linear backoff with 53 retries ~ 1 day
-    my $retries = $settings->{_TRIGGER_JOB_DONE_RETRIES} // 
$ENV{OPENQA_JOB_DONE_HOOK_RETRIES} // 53;
-    my $skip_rc = $settings->{_TRIGGER_JOB_DONE_SKIP_RC} // 
$ENV{OPENQA_JOB_DONE_HOOK_SKIP_RC} // 142;
+    my $retries = $settings->{_TRIGGER_JOB_DONE_RETRIES} // 
$ENV{OPENQA_JOB_DONE_HOOK_RETRIES}
+      // DEFAULT_OPENQA_JOB_DONE_HOOK_RETRIES;
+    my $skip_rc = $settings->{_TRIGGER_JOB_DONE_SKIP_RC} // 
$ENV{OPENQA_JOB_DONE_HOOK_SKIP_RC}
+      // DEFAULT_OPENQA_JOB_DONE_HOOK_SKIP_RC;
     $guard->retry(0);
     my $id = $app->minion->enqueue(
         hook_script => [
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openQA-5.1774854217.24dbd811/lib/OpenQA/UserAgent.pm 
new/openQA-5.1774895777.6c2911d1/lib/OpenQA/UserAgent.pm
--- old/openQA-5.1774854217.24dbd811/lib/OpenQA/UserAgent.pm    2026-03-30 
09:03:37.000000000 +0200
+++ new/openQA-5.1774895777.6c2911d1/lib/OpenQA/UserAgent.pm    2026-03-30 
20:36:17.000000000 +0200
@@ -8,6 +8,7 @@
 use Mojo::File 'path';
 use Mojo::Util 'hmac_sha1_sum';
 use Scalar::Util ();
+use Time::Seconds;
 use Carp;
 
 has [qw(apikey apisecret base_url)];
@@ -25,7 +26,7 @@
 
     # Scheduling a couple of hundred jobs takes quite some time - so we better 
wait a couple of minutes
     # (default is 20 seconds)
-    $self->inactivity_timeout(600);
+    $self->inactivity_timeout(ONE_MINUTE * 10);
 
     # Some urls might redirect to https and then there are internal redirects 
for assets
     $self->max_redirects(3);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openQA-5.1774854217.24dbd811/lib/OpenQA/Utils.pm 
new/openQA-5.1774895777.6c2911d1/lib/OpenQA/Utils.pm
--- old/openQA-5.1774854217.24dbd811/lib/OpenQA/Utils.pm        2026-03-30 
09:03:37.000000000 +0200
+++ new/openQA-5.1774895777.6c2911d1/lib/OpenQA/Utils.pm        2026-03-30 
20:36:17.000000000 +0200
@@ -87,6 +87,7 @@
 
 use constant ONE_SECOND_IN_MICROSECONDS => 1_000_000;
 use constant RANDOM_STRING_DEFAULT_LENGTH => 16;
+use constant DEFAULT_OPENQA_BASE_PORT => 9526;
 
 our $VERSION = sprintf '%d.%03d', q$Revision: 1.12 $ =~ /(\d+)/g;
 our @EXPORT = qw(
@@ -799,7 +800,7 @@
 }
 
 sub service_port ($service) {
-    my $base = $ENV{OPENQA_BASE_PORT} ||= 9526;
+    my $base = $ENV{OPENQA_BASE_PORT} ||= DEFAULT_OPENQA_BASE_PORT;
     my $offsets = {
         webui => 0,
         websocket => 1,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openQA-5.1774854217.24dbd811/lib/OpenQA/WebAPI/Controller/Main.pm 
new/openQA-5.1774895777.6c2911d1/lib/OpenQA/WebAPI/Controller/Main.pm
--- old/openQA-5.1774854217.24dbd811/lib/OpenQA/WebAPI/Controller/Main.pm       
2026-03-30 09:03:37.000000000 +0200
+++ new/openQA-5.1774895777.6c2911d1/lib/OpenQA/WebAPI/Controller/Main.pm       
2026-03-30 20:36:17.000000000 +0200
@@ -6,12 +6,15 @@
 use Feature::Compat::Try;
 
 use Date::Format;
+use Mojo::File qw(path);
+use Time::Seconds;
 use OpenQA::Constants qw(BUILD_SORT_BY_NAME BUILD_SORT_BY_NEWEST_JOB 
BUILD_SORT_BY_OLDEST_JOB);
 use OpenQA::Jobs::Constants;
 use OpenQA::Schema::Result::Jobs;
 use OpenQA::BuildResults;
 use OpenQA::Utils;
-use Mojo::File qw(path);
+
+use constant OPENQA_WEBUI_OVERVIEW_INACTIVITY_TIMEOUT => 
$ENV{OPENQA_WEBUI_OVERVIEW_INACTIVITY_TIMEOUT} // 90;
 
 sub dashboard_build_results ($self) {
     my $validation = $self->validation;
@@ -23,8 +26,9 @@
     $validation->optional('group');
     return $self->reply->validation_error({format => $self->accepts('html', 
'json')}) if $validation->has_error;
 
-    my $limit_builds = $validation->param('limit_builds') // 
$self->app->config->{global}->{frontpage_builds};
-    my $time_limit_days = $validation->param('time_limit_days') // 14;
+    my $config = $self->app->config->{global};
+    my $limit_builds = $validation->param('limit_builds') // 
$config->{frontpage_builds};
+    my $time_limit_days = $validation->param('time_limit_days') // 
$config->{frontpage_time_limit_days};
     my $only_tagged = $validation->param('only_tagged') // 0;
     my $default_expanded = $validation->param('default_expanded') // 0;
     my $show_tags = $validation->param('show_tags') // $only_tagged;
@@ -109,13 +113,13 @@
     return $self->reply->not_found unless my $group = 
$self->schema->resultset($resultset)->find($group_id);
 
     my $fullscreen = $validation->param('fullscreen') // 0;
-    my $interval = $validation->param('interval') // 60;
+    my $interval = $validation->param('interval') // ONE_MINUTE;
     $self->stash(fullscreen => $fullscreen, interval => $interval);
 
     my $page = $validation->param('comments_page') // 1;
     my $page_limit = $validation->param('comments_limit') // 5;
 
-    $self->inactivity_timeout($ENV{OPENQA_WEBUI_OVERVIEW_INACTIVITY_TIMEOUT} 
// 90);
+    $self->inactivity_timeout(OPENQA_WEBUI_OVERVIEW_INACTIVITY_TIMEOUT);
     # find comments
     my $comments = $group->comments;
     my $ordered_comments = $comments->search(
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openQA-5.1774854217.24dbd811/lib/OpenQA/WebAPI/Controller/Step.pm 
new/openQA-5.1774895777.6c2911d1/lib/OpenQA/WebAPI/Controller/Step.pm
--- old/openQA-5.1774854217.24dbd811/lib/OpenQA/WebAPI/Controller/Step.pm       
2026-03-30 09:03:37.000000000 +0200
+++ new/openQA-5.1774895777.6c2911d1/lib/OpenQA/WebAPI/Controller/Step.pm       
2026-03-30 20:36:17.000000000 +0200
@@ -41,6 +41,8 @@
 use Mojo::JSON 'decode_json';
 use Feature::Compat::Try;
 
+use constant AVG_SIMILARITY_THRESHOLD => 70;
+
 sub _init ($self) {
     return 0 unless my $job = 
$self->app->schema->resultset('Jobs')->find($self->param('testid'));
     my %attrs = (rows => 1, order_by => {-desc => 'id'});
@@ -222,7 +224,7 @@
     #  - tags: tags from the screenshot
     my $default_needle = {};
     my $first_needle = $needles[0];
-    if ($first_needle && ($first_needle->{avg_similarity} || 0) > 70) {
+    if ($first_needle && ($first_needle->{avg_similarity} || 0) > 
AVG_SIMILARITY_THRESHOLD) {
         $first_needle->{selected} = 1;
         $default_needle->{tags} = $first_needle->{tags};
         $default_needle->{area} = $first_needle->{matches};
@@ -571,7 +573,7 @@
         # note: the same needle can be shown under different tags, hence the 
selected flag might be occur twice
         #       (even though we check for $has_selection here!)
         my $best_match = $sorted_needles[0];
-        if (!$has_selection && $best_match && $best_match->{avg_similarity} > 
70) {
+        if (!$has_selection && $best_match && $best_match->{avg_similarity} > 
AVG_SIMILARITY_THRESHOLD) {
             $has_selection = $best_match->{selected} = 1;
             $primary_match = $best_match;
         }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openQA-5.1774854217.24dbd811/lib/OpenQA/WebAPI/Plugin/ObsRsync/Task.pm 
new/openQA-5.1774895777.6c2911d1/lib/OpenQA/WebAPI/Plugin/ObsRsync/Task.pm
--- old/openQA-5.1774854217.24dbd811/lib/OpenQA/WebAPI/Plugin/ObsRsync/Task.pm  
2026-03-30 09:03:37.000000000 +0200
+++ new/openQA-5.1774895777.6c2911d1/lib/OpenQA/WebAPI/Plugin/ObsRsync/Task.pm  
2026-03-30 20:36:17.000000000 +0200
@@ -8,6 +8,9 @@
 use OpenQA::Task::SignalGuard;
 use Feature::Compat::Try;
 
+use constant RETRY_INTERVAL_ON_EXCEPTION => 120;
+use constant RETRY_MAX_COUNT_ON_EXCEPTION => 200;
+
 sub register ($self, $app, $conf) {
     $app->minion->add_task(obs_rsync_run => \&run);
     $app->minion->add_task(obs_rsync_update_dirty_status => 
\&update_dirty_status);
@@ -43,9 +46,6 @@
     my $helper = $app->obs_rsync;
     my $home = $helper->home;
 
-    my $retry_interval_on_exception = 120;
-    my $retry_max_count_on_exception = 200;
-
     if ($job->info && !$job->info->{notes}{project_lock}) {
         return _retry_or_finish($job, $helper) unless $helper->lock($project);
         $job->note(project_lock => 1);
@@ -53,7 +53,7 @@
     my $dirty = 0;
     try { $dirty = $helper->is_status_dirty($project, 1) }
     catch ($e) {
-        return _retry_or_finish($job, $helper, $project, 
$retry_interval_on_exception, $retry_max_count_on_exception);
+        return _retry_or_finish($job, $helper, $project, 
RETRY_INTERVAL_ON_EXCEPTION, RETRY_MAX_COUNT_ON_EXCEPTION);
     }
     return _retry_or_finish($job, $helper, $project) if $dirty;
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openQA-5.1774854217.24dbd811/lib/OpenQA/WebSockets/Controller/Worker.pm 
new/openQA-5.1774895777.6c2911d1/lib/OpenQA/WebSockets/Controller/Worker.pm
--- old/openQA-5.1774854217.24dbd811/lib/OpenQA/WebSockets/Controller/Worker.pm 
2026-03-30 09:03:37.000000000 +0200
+++ new/openQA-5.1774895777.6c2911d1/lib/OpenQA/WebSockets/Controller/Worker.pm 
2026-03-30 20:36:17.000000000 +0200
@@ -16,6 +16,7 @@
 use Mojo::Util 'dumper';
 
 use constant LOG_WORKER_STATUS_MESSAGES => 
$ENV{OPENQA_LOG_WORKER_STATUS_MESSAGES} // 0;
+use constant MAX_WEBSOCKET_SIZE => 1024 * 1024 * 10;
 
 sub ws ($self) {
     my $status = $self->status;
@@ -29,7 +30,7 @@
     $self->on(json => \&_message);
     $self->on(finish => \&_finish);
     $self->inactivity_timeout(0);    # Do not force connection close due to 
inactivity
-    $self->tx->max_websocket_size(10485760);
+    $self->tx->max_websocket_size(MAX_WEBSOCKET_SIZE);
 }
 
 sub _finish ($self, $code, $reason) {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openQA-5.1774854217.24dbd811/lib/OpenQA/Worker/Job.pm 
new/openQA-5.1774895777.6c2911d1/lib/OpenQA/Worker/Job.pm
--- old/openQA-5.1774854217.24dbd811/lib/OpenQA/Worker/Job.pm   2026-03-30 
09:03:37.000000000 +0200
+++ new/openQA-5.1774895777.6c2911d1/lib/OpenQA/Worker/Job.pm   2026-03-30 
20:36:17.000000000 +0200
@@ -28,6 +28,8 @@
 use Time::HiRes qw(usleep);
 use Feature::Compat::Try;
 
+use constant DEFAULT_UPLOAD_CHUNK_SIZE => 1_000_000;
+
 # define attributes for public properties
 has 'worker';
 has 'client';
@@ -973,7 +975,7 @@
     my $filename = $upload_parameter->{file}->{filename};
     my $file = $upload_parameter->{file}->{file};
     my $global_settings = $self->worker->settings->global_settings;
-    my $chunk_size = $global_settings->{UPLOAD_CHUNK_SIZE} // 1000000;
+    my $chunk_size = $global_settings->{UPLOAD_CHUNK_SIZE} // 
DEFAULT_UPLOAD_CHUNK_SIZE;
     my $retries = $global_settings->{UPLOAD_RETRIES} // 10;
     my $local_upload = $global_settings->{LOCAL_UPLOAD} // 1;
     my $ua = $self->client->ua;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openQA-5.1774854217.24dbd811/lib/OpenQA/Worker/Settings.pm 
new/openQA-5.1774895777.6c2911d1/lib/OpenQA/Worker/Settings.pm
--- old/openQA-5.1774854217.24dbd811/lib/OpenQA/Worker/Settings.pm      
2026-03-30 09:03:37.000000000 +0200
+++ new/openQA-5.1774895777.6c2911d1/lib/OpenQA/Worker/Settings.pm      
2026-03-30 20:36:17.000000000 +0200
@@ -19,6 +19,8 @@
 has 'webui_host_specific_settings';
 
 use constant VNCPORT_OFFSET => $ENV{VNCPORT_OFFSET} // 90;
+use constant QEMU_PORT_OFFSET => 20_002;
+use constant DEFAULT_CRITICAL_LOAD_AVG_THRESHOLD => 40;
 
 sub new ($class, $instance_number = undef, $cli_options = {}) {
     my $config_paths = lookup_config_files(undef, 'workers.ini', 1);
@@ -48,12 +50,12 @@
 
     # Select sensible system CPU load15 threshold to prevent system overload
     # based on experiences with system stability so far
-    $global_settings{CRITICAL_LOAD_AVG_THRESHOLD} //= 40;
+    $global_settings{CRITICAL_LOAD_AVG_THRESHOLD} //= 
DEFAULT_CRITICAL_LOAD_AVG_THRESHOLD;
 
     # set some environment variables
     # TODO: This should be sent to the scheduler to be included in the 
worker's table.
     if (defined $instance_number) {
-        $ENV{QEMUPORT} = $instance_number * 10 + 20002;
+        $ENV{QEMUPORT} = $instance_number * 10 + QEMU_PORT_OFFSET;
         $ENV{VNC} = $instance_number + VNCPORT_OFFSET;
     }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openQA-5.1774854217.24dbd811/lib/OpenQA/Worker/WebUIConnection.pm 
new/openQA-5.1774895777.6c2911d1/lib/OpenQA/Worker/WebUIConnection.pm
--- old/openQA-5.1774854217.24dbd811/lib/OpenQA/Worker/WebUIConnection.pm       
2026-03-30 09:03:37.000000000 +0200
+++ new/openQA-5.1774895777.6c2911d1/lib/OpenQA/Worker/WebUIConnection.pm       
2026-03-30 20:36:17.000000000 +0200
@@ -15,6 +15,9 @@
 # define it here for now until we can drop support for Leap 15.6
 use constant _HTTP_TOO_EARLY => 425;
 
+use constant DEFAULT_OPENQA_WORKER_CONNECT_RETRIES => 60;
+use constant MAX_WEBSOCKET_SIZE => 1024 * 1024 * 10;
+
 has 'webui_host';    # hostname:port of the web UI to connect to
 has 'url';    # URL of the web UI to connect to - initially deduced from 
webui_host (Mojo::URL instance)
 has 'ua';    # the OpenQA::Client used to do connections
@@ -210,7 +213,7 @@
 
                     # note: The worker is supposed to handle this event and 
e.g. try to re-register again.
                 });
-            $tx->max_websocket_size(10485760);
+            $tx->max_websocket_size(MAX_WEBSOCKET_SIZE);
             $self->websocket_connection($tx);
             $self->send_status();
             $self->_set_status(connected => {});
@@ -265,7 +268,8 @@
 }
 
 sub configured_retries ($self) {
-    $ENV{OPENQA_WORKER_CONNECT_RETRIES} // 
$self->worker->settings->global_settings->{RETRIES} // 60;
+    $ENV{OPENQA_WORKER_CONNECT_RETRIES} // 
$self->worker->settings->global_settings->{RETRIES}
+      // DEFAULT_OPENQA_WORKER_CONNECT_RETRIES;
 }
 
 # sends a command to the web UI via its REST API
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openQA-5.1774854217.24dbd811/lib/OpenQA/Worker.pm 
new/openQA-5.1774895777.6c2911d1/lib/OpenQA/Worker.pm
--- old/openQA-5.1774854217.24dbd811/lib/OpenQA/Worker.pm       2026-03-30 
09:03:37.000000000 +0200
+++ new/openQA-5.1774895777.6c2911d1/lib/OpenQA/Worker.pm       2026-03-30 
20:36:17.000000000 +0200
@@ -51,6 +51,8 @@
 use OpenQA::Worker::Job;
 use OpenQA::Worker::App;
 
+use constant DEFAULT_IPMI_AUTOSHUTDOWN_INTERVAL => 300;
+
 has 'instance_number';
 has 'pool_directory';
 has 'no_cleanup';
@@ -349,7 +351,7 @@
             });
     }
 
-    my $interval = $global_settings->{IPMI_AUTOSHUTDOWN_INTERVAL} // 300;
+    my $interval = $global_settings->{IPMI_AUTOSHUTDOWN_INTERVAL} // 
DEFAULT_IPMI_AUTOSHUTDOWN_INTERVAL;
     if (   $global_settings->{IPMI_HOSTNAME}
         && $global_settings->{IPMI_USER}
         && $global_settings->{IPMI_PASSWORD}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openQA-5.1774854217.24dbd811/t/01-compile-check-all.t 
new/openQA-5.1774895777.6c2911d1/t/01-compile-check-all.t
--- old/openQA-5.1774854217.24dbd811/t/01-compile-check-all.t   2026-03-30 
09:03:37.000000000 +0200
+++ new/openQA-5.1774895777.6c2911d1/t/01-compile-check-all.t   2026-03-30 
20:36:17.000000000 +0200
@@ -5,19 +5,14 @@
 # We need :no_end_test here because otherwise it would output a no warnings
 # test for each of the modules, but with the same test number
 use Test::Warnings qw(:no_end_test :report_warnings);
+use Test::Compile;
+use File::Which;
 use FindBin;
 use lib "$FindBin::Bin/lib", 
"$FindBin::Bin/../external/os-autoinst-common/lib";
 use OpenQA::Test::TimeLimit '400';
 
-use Test::Strict;
 
-push @Test::Strict::MODULES_ENABLING_STRICT, 'Test::Most';
-push @Test::Strict::MODULES_ENABLING_WARNINGS, 'Test::Most';
-
-$Test::Strict::TEST_SYNTAX = 1;
-$Test::Strict::TEST_STRICT = 1;
-$Test::Strict::TEST_WARNINGS = 1;
-$Test::Strict::TEST_SKIP = [
+my $SKIP = [
     # skip test module which would require test API from os-autoinst to be 
present
     
't/data/openqa/share/tests/opensuse/tests/installation/installer_timezone.pm',
     # Skip data files which are supposed to resemble generated output which 
has no 'use' statements
@@ -28,4 +23,34 @@
     't/data/openqa-trigger-from-obs/Proj2::appliances/.dirty_status',
     't/data/openqa-trigger-from-obs/Proj3::standard/empty.txt',
 ];
-all_perl_files_ok(qw(lib script t));
+
+my $test = Test::Compile->new();
+my @files;
+
+# Prevent any non-tracked files or files within .git (e.g. in.git/rr-cache) to
+# interfer
+if (-d '.git' and which('git')) {
+    my $root = qx{git rev-parse --show-toplevel};
+    chomp $root;
+    $root .= '/';
+    my @all_git_files = qx{git ls-files};
+    chomp @all_git_files;
+    my %skip = map { $_ => undef } @$SKIP;
+    @files = map { $root . $_ }
+      grep { !-l $_ && !exists $skip{$_} && $_ !~ /^(external|t)\// } 
@all_git_files;    # Exclude files to skip
+}
+else {
+    @files = ($test->all_pm_files('lib'), $test->all_pl_files('script'));
+    my %skip = map { $_ => undef } @$SKIP;
+    @files = grep { my $f = s{^\./}{}r; !exists $skip{$f} && $f !~ /^t\// } 
@files;
+}
+
+# Only check perl files and skip test scripts (already executed)
+@files = grep { /\.(?:pm|pl|t)$/ } @files;
+
+plan tests => scalar @files;
+
+foreach my $file (@files) {
+    my $ok = $file =~ /\.pm$/ ? $test->pm_file_compiles($file) : 
$test->pl_file_compiles($file);
+    ok $ok, "Syntax check $file";
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openQA-5.1774854217.24dbd811/t/11-commands.t 
new/openQA-5.1774895777.6c2911d1/t/11-commands.t
--- old/openQA-5.1774854217.24dbd811/t/11-commands.t    2026-03-30 
09:03:37.000000000 +0200
+++ new/openQA-5.1774895777.6c2911d1/t/11-commands.t    2026-03-30 
20:36:17.000000000 +0200
@@ -3,24 +3,28 @@
 # SPDX-License-Identifier: GPL-2.0-or-later
 
 use Test::Most;
+use Mojo::Base -signatures;
 
 use FindBin;
 use lib "$FindBin::Bin/lib", 
"$FindBin::Bin/../external/os-autoinst-common/lib";
 use Test::Warnings qw(:all :report_warnings);
 use Test::Output 'stderr_like';
+use Test::Mock::Time;
 use OpenQA::Test::Case;
 use OpenQA::Test::TimeLimit '10';
+use OpenQA::Schema::Result::Workers;
 use OpenQA::WebSockets::Client;
+use OpenQA::Constants qw(WORKER_COMMAND_QUIT);
 use Test::MockModule;
 use Mojolicious;
 use Mojo::Message;
 
 
 my $mock_client = Test::MockModule->new('OpenQA::WebSockets::Client');
-my ($client_called, $last_command);
+my ($client_called, $last_command, $fake_error);
 $mock_client->redefine(
-    send_msg => sub {
-        my ($self, $workerid, $command, $jobid) = @_;
+    send_msg => sub ($self, $workerid, $command, $jobid) {
+        die $fake_error if $fake_error;
         $client_called++;
         $last_command = $command;
     });
@@ -49,6 +53,18 @@
 isnt $last_command, 'foo', 'refuse invalid commands';
 ok $client_called, 'mocked send_msg method has been called';
 
+subtest 'dispatch fails' => sub {
+    my $grace_period = OpenQA::Schema::Result::Workers::WS_SERVER_GRACE_PERIOD;
+    my $expected_msg = qr/Failed.*command.*quit.*to 
websocket.*regarding.*localhost.*foo/;
+    my $send_cmd = sub () { $worker->send_command(command => 
WORKER_COMMAND_QUIT) };
+    $fake_error = 'foo';
+    stderr_like { $send_cmd->() } qr/\[WARN\] $expected_msg/, 'just a warning';
+    sleep $grace_period;
+    stderr_like { $send_cmd->() } qr/\[WARN\] $expected_msg/, 'still a warning 
within grace period';
+    sleep 1;
+    stderr_like { $send_cmd->() } qr/\[ERROR\] $expected_msg/, 'error after 
grace period exceeded';
+};
+
 subtest 'ws server does not try to query itself' => sub {
     OpenQA::WebSockets::Client::mark_current_process_as_websocket_server;
     $last_command = undef;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openQA-5.1774854217.24dbd811/t/17-build_tagging.t 
new/openQA-5.1774895777.6c2911d1/t/17-build_tagging.t
--- old/openQA-5.1774854217.24dbd811/t/17-build_tagging.t       2026-03-30 
09:03:37.000000000 +0200
+++ new/openQA-5.1774895777.6c2911d1/t/17-build_tagging.t       2026-03-30 
20:36:17.000000000 +0200
@@ -141,7 +141,7 @@
         $t->get_ok('/dashboard_build_results?show_tags=' . 
$enabled)->status_is(200);
         is scalar @{$t->tx->res->dom->find('a[href^=/tests/]')},
           9, "all builds shown on index page (show_tags=$enabled)";
-        is scalar @{$t->tx->res->dom->find("i[title='important']")},
+        is scalar @{$t->tx->res->dom->find("span[title='important']")},
           $enabled, "tag (not) shown on index page (show_tags=$enabled)";
     }
 };
@@ -336,22 +336,22 @@
 
     post_comment_1001('tag:5000:important:fallback');
     $t->get_ok('/group_overview/1001')->status_is(200);
-    $t->text_is('#tag-1001-1_2_2-5000 i', 'fallback', 'version 1.2-2 has 
fallback tag');
-    $t->text_is('#tag-1001-1_2_1-5000 i', 'fallback', 'version 1.2-1 has 
fallback tag');
+    $t->text_is('#tag-1001-1_2_2-5000 span.tag', 'fallback', 'version 1.2-2 
has fallback tag');
+    $t->text_is('#tag-1001-1_2_1-5000 span.tag', 'fallback', 'version 1.2-1 
has fallback tag');
 
     post_comment_1001('tag:1.2-2-5000:important:second');
     $t->get_ok('/group_overview/1001')->status_is(200);
-    $t->text_is('#tag-1001-1_2_2-5000 i', 'second', 'version 1.2-2 has 
version-specific tag');
-    $t->text_is('#tag-1001-1_2_1-5000 i', 'fallback', 'version 1.2-1 has still 
fallback tag');
+    $t->text_is('#tag-1001-1_2_2-5000 span.tag', 'second', 'version 1.2-2 has 
version-specific tag');
+    $t->text_is('#tag-1001-1_2_1-5000 span.tag', 'fallback', 'version 1.2-1 
has still fallback tag');
 
     post_comment_1001('tag:1.2-1-5000:important:first');
     $t->get_ok('/group_overview/1001')->status_is(200);
-    $t->text_is('#tag-1001-1_2_2-5000 i', 'second', 'version 1.2-2 has 
version-specific tag');
-    $t->text_is('#tag-1001-1_2_1-5000 i', 'first', 'version 1.2-1 has 
version-specific tag');
+    $t->text_is('#tag-1001-1_2_2-5000 span.tag', 'second', 'version 1.2-2 has 
version-specific tag');
+    $t->text_is('#tag-1001-1_2_1-5000 span.tag', 'first', 'version 1.2-1 has 
version-specific tag');
 
     post_comment_1001('tag:1.2-1-5000:important:label-with.specialchars');
     $t->get_ok('/group_overview/1001')->status_is(200);
-    $t->text_is('#tag-1001-1_2_1-5000 i', 'label-with.specialchars', 'version 
1.2-1 has version-specific tag');
+    $t->text_is('#tag-1001-1_2_1-5000 span.tag', 'label-with.specialchars', 
'version 1.2-1 has version-specific tag');
 };
 
 subtest 'content negotiation' => sub {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openQA-5.1774854217.24dbd811/t/22-dashboard.t 
new/openQA-5.1774895777.6c2911d1/t/22-dashboard.t
--- old/openQA-5.1774854217.24dbd811/t/22-dashboard.t   2026-03-30 
09:03:37.000000000 +0200
+++ new/openQA-5.1774895777.6c2911d1/t/22-dashboard.t   2026-03-30 
20:36:17.000000000 +0200
@@ -225,7 +225,7 @@
       'link URLs';
 
     $t->element_count_is("div.children-$default_expanded .badge-all-passed", 
1, 'badge shown on parent-level');
-    $t->element_count_is("div.children-$default_expanded .h4 span i.tag", 0, 
'no tags shown yet');
+    $t->element_count_is("div.children-$default_expanded .h4 span span.tag", 
0, 'no tags shown yet');
 }
 check_test_parent('collapsed');
 
@@ -250,15 +250,15 @@
 
 sub check_tags {
     
$t->get_ok('/dashboard_build_results?limit_builds=20&show_tags=1')->status_is(200);
-    my @tags = $t->tx->res->dom->find('div.children-collapsed span 
i.tag')->map('text')->each;
+    my @tags = $t->tx->res->dom->find('div.children-collapsed span 
span.tag')->map('text')->each;
     is_deeply \@tags, ['some_tag'], 'tag is shown on parent-level';
 
     $t->get_ok('/parent_group_overview/' . $test_parent->id . 
'?limit_builds=20&show_tags=1')->status_is(200);
-    @tags = $t->tx->res->dom->find('div.children-expanded span 
i.tag')->map('text')->each;
+    @tags = $t->tx->res->dom->find('div.children-expanded span 
span.tag')->map('text')->each;
     is_deeply \@tags, ['some_tag'], 'tag is shown on parent-level';
 
     
$t->get_ok('/dashboard_build_results?limit_builds=20&only_tagged=1')->status_is(200);
-    @tags = $t->tx->res->dom->find('div.children-collapsed span 
i.tag')->map('text')->each;
+    @tags = $t->tx->res->dom->find('div.children-collapsed span 
span.tag')->map('text')->each;
     is_deeply \@tags, ['some_tag'], 'tag is shown on parent-level (only 
tagged)';
     @h4 = $t->tx->res->dom->find('div.children-collapsed .h4 
a')->map('text')->each;
     is_deeply \@h4, ['Build0092'], 'only tagged builds on parent-level shown';
@@ -272,7 +272,7 @@
 # use version-build format where version doesn't matches
 $tag_for_0092_comment->update({text => 'tag:5-0092:important:some_tag', 
user_id => 99901});
 
$t->get_ok('/dashboard_build_results?limit_builds=20&only_tagged=1')->status_is(200);
-my @tags = $t->tx->res->dom->find('div.children-collapsed .h4 span 
i.tag')->map('text')->each;
+my @tags = $t->tx->res->dom->find('div.children-collapsed .h4 span 
span.tag')->map('text')->each;
 is_deeply \@tags, [], 'tag is not shown on parent-level because version does 
not match';
 @h4 = $t->tx->res->dom->find('div.children-collapsed .h4 
a')->map('text')->each;
 is_deeply \@h4, [], 'also no tagged builds on parent-level shown';
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openQA-5.1774854217.24dbd811/t/25-cache-service.t 
new/openQA-5.1774895777.6c2911d1/t/25-cache-service.t
--- old/openQA-5.1774854217.24dbd811/t/25-cache-service.t       2026-03-30 
09:03:37.000000000 +0200
+++ new/openQA-5.1774895777.6c2911d1/t/25-cache-service.t       2026-03-30 
20:36:17.000000000 +0200
@@ -132,7 +132,7 @@
     qr/rsync error:.*/, 'rsync error message';
 
     my $status2 = $cache_client->status($rsync_request2);
-    is $status2->result, 'exit code 11', "exit code ok, run $run";
+    is $status2->result, 'exit code 23', "exit code as expected, run $run";
     ok $status2->output, "output ok, run $run";
 
     like $status2->output, qr/Calling: rsync .* --timeout 1800 .*/s, "output 
correct, run $run"
@@ -663,6 +663,18 @@
 
 subtest 'OpenQA::CacheService::Task::Sync' => sub {
     test_sync $_ for (1 .. 4);
+
+    subtest 'Sync to non-existent parent' => sub {
+        my $from = tempdir;
+        $from->child('testfile')->spew('some data');
+        my $to = tempdir->child('non_existent_parent')->child('target_host');
+        my $rsync_request = $cache_client->rsync_request(from => $from, to => 
$to);
+        ok !$cache_client->enqueue($rsync_request);
+        perform_minion_jobs($t->app->minion);
+        wait_for_or_bail_out { 
$cache_client->status($rsync_request)->is_processed } 'rsync';
+        is $cache_client->status($rsync_request)->result, 'exit code 0', 'Sync 
successful with missing parent';
+        ok -e $to->child('tests')->child('testfile'), 'File synced correctly';
+    };
 };
 
 done_testing;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openQA-5.1774854217.24dbd811/t/35-script_clone_job.t 
new/openQA-5.1774895777.6c2911d1/t/35-script_clone_job.t
--- old/openQA-5.1774854217.24dbd811/t/35-script_clone_job.t    2026-03-30 
09:03:37.000000000 +0200
+++ new/openQA-5.1774895777.6c2911d1/t/35-script_clone_job.t    2026-03-30 
20:36:17.000000000 +0200
@@ -58,6 +58,19 @@
     qr/can't exec/i, 'exec error logged';
     like $run->('false'), qr/false.*exited.*1/i, 'error if command fails';
     is $run->('true'), '', 'no error if command succeeds';
+
+    subtest 'get URL from command' => sub {
+        my $url_from_cmd = \&OpenQA::Script::CloneJob::_url_from_cmd;
+        my $res = $url_from_cmd->(echo => qw(-n http://foo/bar));
+        is $res, 'http://foo/bar', 'got URL';
+        is ref $res, 'Mojo::URL', 'URL returned as Mojo::URL ref';
+        combined_like { $res = $url_from_cmd->('does-not-exist') } qr/can't 
exec/i, 'exec error logged';
+        like $res, qr/Failed.*does-not-exist.*No such/i, 'got error via 
_url_from_cmd';
+        is ref $res, '', 'error returned as scalar';
+        $res = $url_from_cmd->('false');
+        like $res, qr/false.*exited.*status 1/i, 'got error via _url_from_cmd 
for non-zero return exit status';
+        is ref $res, '', 'error for non-zero exit status returned as scalar';
+    };
 };
 
 subtest 'getting job' => sub {
@@ -493,25 +506,25 @@
 subtest 'invoking curl passing auth headers' => sub {
     my $clone_mock = Test::MockModule->new('OpenQA::Script::CloneJob');
     my @invoked_cmds;
-    $clone_mock->redefine(
-        _run_cmd => sub (@args) {
-            push @invoked_cmds, map { m/(.*hash:|.*time:)/i ? "$1 ?" : "$_" } 
@args;
-            '';
-        });
+    my $record_cmd = sub (@args) {
+        push @invoked_cmds, [map { m/(.*hash:|.*time:)/i ? "$1 ?" : "$_" } 
@args];
+    };
+    $clone_mock->redefine(_run_cmd => sub (@args) { $record_cmd->(@args); '' 
});
+    $clone_mock->redefine(_url_from_cmd => sub (@args) { $record_cmd->(@args); 
Mojo::URL->new('redirected-url') });
     note 'config path: ' . ($ENV{OPENQA_CONFIG} = "$FindBin::Bin/data");
 
     my $args = OpenQA::Script::CloneJob::make_curl_arguments({retry => 5});
-    my @expected_default_args = qw(--follow --retry 5 --retry-connrefused 
--no-progress-meter);
+    my @expected_default_args = qw(--retry 5 --retry-connrefused 
--no-progress-meter);
     is_deeply $args, \@expected_default_args, 'default arguments correct';
     my $secrets = OpenQA::Script::CloneJob::read_secrets('testapi');
     is_deeply $secrets, [qw(PERCIVALKEY02 PERCIVALSECRET02)], 'key and secret 
as expected for host "testapi"';
 
     my %url_handler = (curl_args => $args, secrets => $secrets);
     my $error = OpenQA::Script::CloneJob::mirror(\%url_handler, 
Mojo::URL->new('url'), 'path');
+    push @expected_default_args, map { -H => $_ } ('X-API-Hash: ?', 
'X-API-Key: PERCIVALKEY02', 'X-API-Microtime: ?');
     my @expected_cmds = (
-        curl => @expected_default_args,
-        (map { -H => $_ } ('X-API-Hash: ?', 'X-API-Key: PERCIVALKEY02', 
'X-API-Microtime: ?')),
-        qw(--continue-at - --output path url),
+        [curl => @expected_default_args, qw(--silent --follow --head --output 
/dev/null -w %{url_effective} url)],
+        [curl => @expected_default_args, qw(--continue-at - --output path 
redirected-url)],
     );
     is $error, '', 'no error returned';
     is_deeply \@invoked_cmds, \@expected_cmds, 'invoked expected commands' or 
always_explain \@invoked_cmds;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openQA-5.1774854217.24dbd811/t/api/04-jobs.t 
new/openQA-5.1774895777.6c2911d1/t/api/04-jobs.t
--- old/openQA-5.1774854217.24dbd811/t/api/04-jobs.t    2026-03-30 
09:03:37.000000000 +0200
+++ new/openQA-5.1774895777.6c2911d1/t/api/04-jobs.t    2026-03-30 
20:36:17.000000000 +0200
@@ -884,7 +884,7 @@
     is_deeply find_most_recent_event($schema, 'job_cancel'), {id => 99963, 
reason => undef}, 'cancellation was logged';
 
     $jobs->search({id => 99963})->update({assigned_worker_id => 1, result => 
NONE});
-    combined_like { $t->post_ok('/api/v1/jobs/99963/cancel?reason=Undecided') 
} qr/Failed dispatching message/s,
+    combined_like { $t->post_ok('/api/v1/jobs/99963/cancel?reason=Undecided') 
} qr/Failed to send command "cancel"/s,
       'tried to send cancellation to worker';
     $t->status_is(200, 'cancellation considered successful even if sending 
command to worker failed');
     is_deeply find_most_recent_event($schema, 'job_cancel'), {id => 99963, 
reason => 'Undecided'},
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openQA-5.1774854217.24dbd811/t/ui/18-tests-details.t 
new/openQA-5.1774895777.6c2911d1/t/ui/18-tests-details.t
--- old/openQA-5.1774854217.24dbd811/t/ui/18-tests-details.t    2026-03-30 
09:03:37.000000000 +0200
+++ new/openQA-5.1774895777.6c2911d1/t/ui/18-tests-details.t    2026-03-30 
20:36:17.000000000 +0200
@@ -496,14 +496,40 @@
       'video src correct and starts on timestamp';
 };
 
+subtest 'arrow key navigation between steps' => sub {
+    $driver->get('/tests/99946');
+    wait_for_ajax(msg => 'test 99946 loaded');
+    $driver->find_element_by_link_text('Details')->click();
+    wait_for_ajax(msg => 'details tab loaded');
+
+    $driver->find_element('[href="#step/bootloader/1"]')->click();
+    wait_for_ajax(msg => 'first step of bootloader loaded');
+    my $first_step_url = $driver->get_current_url();
+    like $first_step_url, qr/#step\/bootloader\/1/, 'first step selected';
+
+    $driver->execute_script("\$(window).trigger(\$.Event('keydown', {key: 
'ArrowRight'}))");
+    wait_for_ajax(msg => 'arrow right pressed via jQuery');
+    my $second_step_url = $driver->get_current_url();
+    like $second_step_url, qr/#step\/bootloader\/2/, 'second step selected 
after right arrow';
+
+    $driver->execute_script("\$(window).trigger(\$.Event('keydown', {key: 
'ArrowLeft'}))");
+    wait_for_ajax(msg => 'arrow left pressed via jQuery');
+    my $back_to_first_url = $driver->get_current_url();
+    like $back_to_first_url, qr/#step\/bootloader\/1/, 'back to first step 
after left arrow';
+
+    $driver->execute_script("\$(window).trigger(\$.Event('keydown', {key: 
'Escape'}))");
+    wait_for_ajax(msg => 'escape pressed to close preview');
+};
+
 subtest 'misc details: title, favicon, go back, go to source view, go to log 
view' => sub {
-    $driver->go_back();    # to 99946
+    $driver->get('/tests/99946');
+    wait_for_ajax(msg => 'test 99946 loaded');
     $driver->title_is('openQA: opensuse-13.1-DVD-i586-Build0091-textmode@32bit 
test results', 'tests/99946 followed');
     like $driver->find_element('link[rel=icon]')->get_attribute('href'),
       qr/logo-passed/, 'favicon is based on job result';
     wait_for_ajax(msg => 'test details tab for job 99946 loaded (1)');
-    if (ok my $current_preview = $driver->find_element('.current_preview'), 
'state preserved when going back') {
-        $current_preview->click;
+    if (my @previews = $driver->find_elements('.current_preview')) {
+        $previews[0]->click;    # uncoverable statement
     }
     $driver->find_element_by_link_text('installer_timezone')->click();
     like
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openQA-5.1774854217.24dbd811/templates/webapi/main/group_builds.html.ep 
new/openQA-5.1774895777.6c2911d1/templates/webapi/main/group_builds.html.ep
--- old/openQA-5.1774854217.24dbd811/templates/webapi/main/group_builds.html.ep 
2026-03-30 09:03:37.000000000 +0200
+++ new/openQA-5.1774895777.6c2911d1/templates/webapi/main/group_builds.html.ep 
2026-03-30 20:36:17.000000000 +0200
@@ -29,7 +29,7 @@
                 %= include 'main/review_badge', group_build_id => 
$group_build_id, build_res => $build_res, id_prefix => ''
                 % if (my $tag = $build_res->{tag}) {
                     <span id="tag-<%= $group_build_id %>">
-                        <i class="tag fa-solid fa-tag" title="<%= 
$tag->{type}; %>"><%= $tag->{description} %></i>
+                        <span class="tag" title="<%= $tag->{type}; %>"><i 
class="fa-solid fa-tag"></i><%= $tag->{description} %></span>
                     </span>
                 % }
             </span>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openQA-5.1774854217.24dbd811/templates/webapi/main/group_builds_functionality_view.html.ep
 
new/openQA-5.1774895777.6c2911d1/templates/webapi/main/group_builds_functionality_view.html.ep
--- 
old/openQA-5.1774854217.24dbd811/templates/webapi/main/group_builds_functionality_view.html.ep
      2026-03-30 09:03:37.000000000 +0200
+++ 
new/openQA-5.1774895777.6c2911d1/templates/webapi/main/group_builds_functionality_view.html.ep
      2026-03-30 20:36:17.000000000 +0200
@@ -31,7 +31,7 @@
 
                 % if (my $tag = $build_res->{tag}) {
                     <span id="tag-byGroup-<%= $group_build_id %>">
-                        <i class="tag-byGroup fa-solid fa-tag" title="<%= 
$tag->{type}; %>"><%= $tag->{description} %></i>
+                        <span class="tag-byGroup" title="<%= $tag->{type}; 
%>"><i class="fa-solid fa-tag"></i><%= $tag->{description} %></span>
                     </span>
                 % }
             </div>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openQA-5.1774854217.24dbd811/templates/webapi/main/index.html.ep 
new/openQA-5.1774895777.6c2911d1/templates/webapi/main/index.html.ep
--- old/openQA-5.1774854217.24dbd811/templates/webapi/main/index.html.ep        
2026-03-30 09:03:37.000000000 +0200
+++ new/openQA-5.1774895777.6c2911d1/templates/webapi/main/index.html.ep        
2026-03-30 20:36:17.000000000 +0200
@@ -56,11 +56,11 @@
                 <strong style="display: block;">Limit builds</strong>
                 <p class="d-flex flex-row align-items-center p-1">
                     <label class="form-label">Maximum number of builds per 
group</label>
-                    <input type="number" class="form-control" 
name="limit_builds" value="3" id="filter-limit-builds">
+                    <input type="number" class="form-control" 
name="limit_builds" value="<%= app->config->{global}->{frontpage_builds} %>" 
id="filter-limit-builds">
                 </p>
                 <p class="d-flex flex-row align-items-center p-1">
                     <label class="form-label">Maximum age in days</label>
-                    <input type="number" class="form-control" 
name="time_limit_days" value="14" id="filter-time-limit-days">
+                    <input type="number" class="form-control" 
name="time_limit_days" value="<%= 
app->config->{global}->{frontpage_time_limit_days} %>" 
id="filter-time-limit-days">
                 </p>
             </div>
             <div class="mb-3">
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openQA-5.1774854217.24dbd811/tools/ci/ci-packages.txt 
new/openQA-5.1774895777.6c2911d1/tools/ci/ci-packages.txt
--- old/openQA-5.1774854217.24dbd811/tools/ci/ci-packages.txt   2026-03-30 
09:03:37.000000000 +0200
+++ new/openQA-5.1774895777.6c2911d1/tools/ci/ci-packages.txt   2026-03-30 
20:36:17.000000000 +0200
@@ -229,6 +229,7 @@
 perl-TAP-Harness-JUnit-0.42
 perl-Task-Weaken-1.06
 perl-Test-CheckGitStatus-0.1.2
+perl-Test-Compile
 perl-Test-Deep-1.205.0
 perl-Test-Differences-0.710.0
 perl-Test-Exception-0.430000
@@ -241,7 +242,6 @@
 perl-Test-Output-1.034
 perl-Test-Perl-Critic-1.40.0
 perl-Test-Pod-1.52
-perl-Test-Strict-0.52
 perl-Test-Warn-0.37
 perl-Test-Warnings-0.38.0
 perl-Text-Brew-0.02

++++++ openQA.obsinfo ++++++
--- /var/tmp/diff_new_pack.FLRthc/_old  2026-03-31 15:29:24.542074092 +0200
+++ /var/tmp/diff_new_pack.FLRthc/_new  2026-03-31 15:29:24.554074592 +0200
@@ -1,5 +1,5 @@
 name: openQA
-version: 5.1774854217.24dbd811
-mtime: 1774854217
-commit: 24dbd8114efeea41ee484b56c5b3c633d6b5ac97
+version: 5.1774895777.6c2911d1
+mtime: 1774895777
+commit: 6c2911d1c93911b8621226c14ceb6332e0e2dd45
 

Reply via email to