From 12e1e72d566dfab3a214e9d5c7f6ef108295d4a6 Mon Sep 17 00:00:00 2001
From: Mike McLean <mikem@redhat.com>
Date: Feb 10 2026 19:09:13 +0000
Subject: [PATCH 1/9] stab at simpler lag logic


---

diff --git a/kojihub/repos.py b/kojihub/repos.py
index ba92d11..08ac5ee 100644
--- a/kojihub/repos.py
+++ b/kojihub/repos.py
@@ -492,7 +492,6 @@ def do_auto_requests():
     reqs = {}
     dups = {}
     default_lag = context.opts['RepoAutoLag']
-    window = context.opts['RepoLagWindow']
     for tag_id in auto_tags:
         # choose min_event similar to default_min_event, but different lag
         # TODO unify code?
@@ -503,16 +502,7 @@ def do_auto_requests():
             logger.error('No last event for tag %i', tag_id)
             continue
         lag = lags.get(tag_id, default_lag)
-        base_ts = time.time() - lag
-        base_ts = (base_ts // window) * window
-        base_ev = context.handlers.get('getLastEvent')(before=base_ts, strict=False)
-        if base_ev:
-            base = base_ev['id']
-        else:
-            # this will only happen with a brand new instance
-            base = kojihub.tag_first_change_event(tag_id)
-            logger.debug(f'No event older than {base_ts}, using first tag event {base}')
-        check = request_repo(tag_id, min_event=min(base, last), priority=5)
+        check = request_repo(tag_id, priority=5, lag=lag)
         # lower priority so they don't block on-demand
         if check['duplicate']:
             dups[tag_id] = check
@@ -704,7 +694,7 @@ def convert_repo_opts(opts, strict=False):
     return new_opts
 
 
-def request_repo(tag, min_event=None, at_event=None, opts=None, priority=None, force=False):
+def request_repo(tag, min_event=None, at_event=None, opts=None, priority=None, force=False, lag=None):
     """Request a repo for a tag
 
     :param int|str taginfo: tag id or name
@@ -712,6 +702,7 @@ def request_repo(tag, min_event=None, at_event=None, opts=None, priority=None, f
     :param int at_event: specific event for the repo (optional)
     :param dict opts: custom repo options (optional)
     :param bool force: force request creation, even if a matching repo exists
+    :param int lag: set min_event using a lag value (in seconds)
 
     The special value min_event="last" uses the most recent event for the tag
     Otherwise min_event should be an integer
@@ -726,6 +717,9 @@ def request_repo(tag, min_event=None, at_event=None, opts=None, priority=None, f
     opts = convert_repo_opts(opts, strict=True)
     if opts.get('maven') and not context.opts.get('EnableMaven'):
         raise koji.GenericError('Maven support not enabled')
+    if lag is not None:
+        if min_event is not None or at_event is not None:
+            raise koji.ParameterError('The lag option cannot be used with event options')
     if at_event is not None:
         if min_event is not None:
             raise koji.ParameterError('The min_event and at_event options conflict')
@@ -737,7 +731,7 @@ def request_repo(tag, min_event=None, at_event=None, opts=None, priority=None, f
         min_event = kojihub.tag_last_change_event(taginfo['id'])
         logger.debug('Using last event %s for repo request', min_event)
     elif min_event is None:
-        min_event = default_min_event(taginfo)
+        min_event = default_min_event(taginfo, lag=lag)
         logger.debug('Using event %s for repo request', min_event)
     else:
         min_event = kojihub.convert_value(min_event, cast=int)
@@ -799,7 +793,9 @@ def request_repo(tag, min_event=None, at_event=None, opts=None, priority=None, f
         'priority': priority,
         'tag_id': taginfo['id'],
         'at_event': at_event,
-        'min_event': min_event,
+        'min_event': kojihub.tag_last_change_event(taginfo['id']),
+        # TODO - avoid getting last event twice
+        # OR just use getLastEvent?
         'opts': json.dumps(opts),
     }
     insert = InsertProcessor('repo_queue', data=data)
@@ -812,21 +808,18 @@ def request_repo(tag, min_event=None, at_event=None, opts=None, priority=None, f
     return ret
 
 
-def default_min_event(taginfo):
+def default_min_event(taginfo, lag=None):
     """Get the default min_event for repo requests"""
+    if lag is not None:
+        lag = taginfo['extra'].get('repo.lag')
+        if lag is not None and not isinstance(lag, int):
+            logger.warning('Invalid repo.lag setting for tag %s: %r', taginfo['name'], lag)
+            lag = None
+        if lag is None:
+            lag = context.opts['RepoLag']
     last = kojihub.tag_last_change_event(taginfo['id'])
     # last event cannot be None for a valid tag
-    lag = taginfo['extra'].get('repo.lag')
-    if lag is not None and not isinstance(lag, int):
-        logger.warning('Invalid repo.lag setting for tag %s: %r', taginfo['name'], lag)
-        lag = None
-    if lag is None:
-        lag = context.opts['RepoLag']
-    window = context.opts['RepoLagWindow']
     base_ts = time.time() - lag
-    # We round base_ts to nearest window so that duplicate requests will get same event if they
-    # are close in time.
-    base_ts = (base_ts // window) * window
     base_ev = context.handlers.get('getLastEvent')(before=base_ts, strict=False)
     if base_ev:
         base = base_ev['id']

From 8d9b5b7e65eaa785fbfe8f9f41f3a5f402fb708d Mon Sep 17 00:00:00 2001
From: Mike McLean <mikem@redhat.com>
Date: Feb 10 2026 19:09:13 +0000
Subject: [PATCH 2/9] flake8


---

diff --git a/kojihub/repos.py b/kojihub/repos.py
index 08ac5ee..9c3f374 100644
--- a/kojihub/repos.py
+++ b/kojihub/repos.py
@@ -694,7 +694,8 @@ def convert_repo_opts(opts, strict=False):
     return new_opts
 
 
-def request_repo(tag, min_event=None, at_event=None, opts=None, priority=None, force=False, lag=None):
+def request_repo(tag, min_event=None, at_event=None, opts=None, priority=None, force=False,
+                 lag=None):
     """Request a repo for a tag
 
     :param int|str taginfo: tag id or name

From ebc9922c94333f8ba24432b84c88f13fd701f31a Mon Sep 17 00:00:00 2001
From: Mike McLean <mikem@redhat.com>
Date: Feb 10 2026 19:09:13 +0000
Subject: [PATCH 3/9] unit tests + fixes


---

diff --git a/kojihub/repos.py b/kojihub/repos.py
index 9c3f374..cadc433 100644
--- a/kojihub/repos.py
+++ b/kojihub/repos.py
@@ -811,7 +811,7 @@ def request_repo(tag, min_event=None, at_event=None, opts=None, priority=None, f
 
 def default_min_event(taginfo, lag=None):
     """Get the default min_event for repo requests"""
-    if lag is not None:
+    if lag is None:
         lag = taginfo['extra'].get('repo.lag')
         if lag is not None and not isinstance(lag, int):
             logger.warning('Invalid repo.lag setting for tag %s: %r', taginfo['name'], lag)
diff --git a/tests/test_hub/test_repo_requests.py b/tests/test_hub/test_repo_requests.py
index 8beecb1..2becf6b 100644
--- a/tests/test_hub/test_repo_requests.py
+++ b/tests/test_hub/test_repo_requests.py
@@ -16,7 +16,7 @@ IP = repos.InsertProcessor
 UP = repos.UpdateProcessor
 TASK = kojihub.Task
 
-
+import pytest
 class MyError(Exception):
     pass
 
@@ -713,13 +713,13 @@ class TestAutoRequests(BaseTest):
             {'tag_id': 99, 'key': 'repo.auto', 'value': 'true'},
         ]
         self.query_execute.return_value = autokeys
-        self.getLastEvent.return_value = {'id': 1050}
         self.tag_last_change_event.return_value = 1000
         self.request_repo.return_value = {'repo': None, 'request': 'REQ', 'duplicate': False}
 
         repos.do_auto_requests()
 
-        self.request_repo.assert_called_once_with(99, min_event=1000, priority=5)
+        lag = self.context.opts['RepoAutoLag']
+        self.request_repo.assert_called_once_with(99, priority=5, lag=lag)
 
     def test_no_tags(self):
         autokeys = []
@@ -735,13 +735,13 @@ class TestAutoRequests(BaseTest):
         ]
         # the bad rows should be ignored without blocking other auto requests
         self.query_execute.return_value = autokeys
-        self.getLastEvent.return_value = {'id': 1050}
         self.tag_last_change_event.return_value = 1000
         self.request_repo.return_value = {'repo': None, 'request': 'REQ', 'duplicate': False}
 
         repos.do_auto_requests()
 
-        self.request_repo.assert_called_once_with(99, min_event=1000, priority=5)
+        lag = self.context.opts['RepoAutoLag']
+        self.request_repo.assert_called_once_with(99, priority=5, lag=lag)
 
     def test_blocked_row(self):
         autokeys = [
@@ -750,13 +750,13 @@ class TestAutoRequests(BaseTest):
         ]
         # the blocked row should be ignored without blocking other auto requests
         self.query_execute.return_value = autokeys
-        self.getLastEvent.return_value = {'id': 1050}
         self.tag_last_change_event.return_value = 1000
         self.request_repo.return_value = {'repo': None, 'request': 'REQ', 'duplicate': False}
 
         repos.do_auto_requests()
 
-        self.request_repo.assert_called_once_with(99, min_event=1000, priority=5)
+        lag = self.context.opts['RepoAutoLag']
+        self.request_repo.assert_called_once_with(99, priority=5, lag=lag)
 
     def test_auto_lag(self):
         # use a trivial window to simplify the lag calculation
@@ -768,15 +768,12 @@ class TestAutoRequests(BaseTest):
         now = 1717171717
         self.time.return_value = now
         self.query_execute.return_value = autokeys
-        self.getLastEvent.return_value = {'id': 1050}
         self.tag_last_change_event.return_value = 1000
         self.request_repo.return_value = {'repo': None, 'request': 'REQ', 'duplicate': True}
 
         repos.do_auto_requests()
 
-        self.request_repo.assert_called_once_with(99, min_event=1000, priority=5)
-        # with zero lag, getLastEvent should be called with current time
-        self.getLastEvent.assert_called_once_with(before=now, strict=False)
+        self.request_repo.assert_called_once_with(99, priority=5, lag=0)
 
     def test_auto_lag_window(self):
         self.context.opts['RepoLagWindow'] = 600
@@ -787,19 +784,12 @@ class TestAutoRequests(BaseTest):
         now = 1717171717
         self.time.return_value = now
         self.query_execute.return_value = autokeys
-        self.getLastEvent.return_value = {'id': 1050}
         self.tag_last_change_event.return_value = 1000
         self.request_repo.return_value = {'repo': None, 'request': 'REQ', 'duplicate': False}
 
         repos.do_auto_requests()
 
-        self.request_repo.assert_called_once_with(99, min_event=1000, priority=5)
-        # with zero lag, getLastEvent should be called with current time
-        self.getLastEvent.assert_called_once()
-        before = self.getLastEvent.call_args.kwargs['before']
-        # should be earlier than current time, but within lag window
-        if before > now or before < now - 600:
-            raise Exception('Invalid lag calculation')
+        self.request_repo.assert_called_once_with(99, priority=5, lag=0)
 
     def test_no_last_tag_event(self):
         # corner case that should not happen
@@ -814,6 +804,7 @@ class TestAutoRequests(BaseTest):
         self.request_repo.assert_not_called()
         self.tag_last_change_event.assert_called_once()
 
+    @pytest.mark.skip
     def test_no_last_event(self):
         # corner case that can happen with very new instances
         autokeys = [
@@ -827,7 +818,8 @@ class TestAutoRequests(BaseTest):
 
         repos.do_auto_requests()
 
-        self.request_repo.assert_called_once_with(99, min_event=990, priority=5)
+        lag = self.context.opts['RepoAutoLag']
+        self.request_repo.assert_called_once_with(99, priority=5, lag=lag)
         self.tag_last_change_event.assert_called_once()
         self.tag_first_change_event.assert_called_once()
 
@@ -1058,13 +1050,14 @@ class TestRequestRepo(BaseTest):
         ev = 100001
         self.get_repo.return_value = None
         self.RepoQueueQuery.return_value.execute.return_value = []
+        self.tag_last_change_event.return_value = ev + 10
 
         repos.request_repo('TAGID', min_event=ev, priority=5)
 
         # check all the calls made with the value
         self.InsertProcessor.assert_called_once()
         data = self.InsertProcessor.call_args.kwargs['data']
-        self.assertEqual(data['min_event'], ev)
+        self.assertEqual(data['min_event'], ev + 10)  # tag last change
         self.assertEqual(data['priority'], 25)  # default + 5
 
     def test_request_priority_lower_than_existing(self):
@@ -1187,13 +1180,13 @@ class TestRequestRepo(BaseTest):
         self.assertEqual(self.inserts, [])
 
     def test_request_new_req(self):
-        # if a matching request exists, we should return it
         self.get_tag.return_value = {'id': 100, 'name': 'TAG', 'extra': {}}
         self.get_repo.return_value = None
         self.RepoQueueQuery.return_value.execute.return_value = []
         self.RepoQueueQuery.return_value.executeOne.return_value = 'NEW-REQ'
         self.nextval.return_value = 'NEW-ID'
         self.context.session.user_id = 'USER'
+        self.tag_last_change_event.return_value = 101020
 
         result = repos.request_repo('TAG', min_event=101010)
 
@@ -1205,7 +1198,7 @@ class TestRequestRepo(BaseTest):
             'priority': 20,
             'tag_id': 100,
             'at_event': None,
-            'min_event': 101010,
+            'min_event': 101020,  # tag last change event
             'opts': '{}',
         }
         self.assertEqual(self.inserts[0].data, expect)

From 228279f603870186d62f40348368db8f56db7ca5 Mon Sep 17 00:00:00 2001
From: Mike McLean <mikem@redhat.com>
Date: Feb 10 2026 19:09:13 +0000
Subject: [PATCH 4/9] coverage, cleanup


---

diff --git a/tests/test_hub/test_repo_requests.py b/tests/test_hub/test_repo_requests.py
index 2becf6b..94fdf28 100644
--- a/tests/test_hub/test_repo_requests.py
+++ b/tests/test_hub/test_repo_requests.py
@@ -16,7 +16,6 @@ IP = repos.InsertProcessor
 UP = repos.UpdateProcessor
 TASK = kojihub.Task
 
-import pytest
 class MyError(Exception):
     pass
 
@@ -804,27 +803,6 @@ class TestAutoRequests(BaseTest):
         self.request_repo.assert_not_called()
         self.tag_last_change_event.assert_called_once()
 
-    @pytest.mark.skip
-    def test_no_last_event(self):
-        # corner case that can happen with very new instances
-        autokeys = [
-            {'tag_id': 99, 'key': 'repo.auto', 'value': 'true'},
-        ]
-        self.getLastEvent.return_value = None
-        self.query_execute.return_value = autokeys
-        self.tag_last_change_event.return_value = 1000
-        self.tag_first_change_event.return_value = 990
-        self.request_repo.return_value = {'repo': None, 'request': 'REQ', 'duplicate': False}
-
-        repos.do_auto_requests()
-
-        lag = self.context.opts['RepoAutoLag']
-        self.request_repo.assert_called_once_with(99, priority=5, lag=lag)
-        self.tag_last_change_event.assert_called_once()
-        self.tag_first_change_event.assert_called_once()
-
-        repos.do_auto_requests()
-
 
 class TestGetRepo(BaseTest):
 
@@ -1123,6 +1101,18 @@ class TestRequestRepo(BaseTest):
         self.InsertProcessor.assert_not_called()
         self.get_repo.assert_not_called()
 
+    def test_lag_conflict(self):
+        self.get_tag.return_value = {'id': 100, 'name': 'TAG', 'extra': {}}
+
+        with self.assertRaises(koji.ParameterError):
+            repos.request_repo('TAGID', min_event=100, lag=10)
+
+        with self.assertRaises(koji.ParameterError):
+            repos.request_repo('TAGID', at_event=100, lag=10)
+
+        self.InsertProcessor.assert_not_called()
+        self.get_repo.assert_not_called()
+
     def test_bad_at_event(self):
         self.get_tag.return_value = {'id': 100, 'name': 'TAG', 'extra': {}}
         self.getEvent.return_value = None

From d59729c54bcecf58d4732f82e9cd23bf5ca5dac0 Mon Sep 17 00:00:00 2001
From: Mike McLean <mikem@redhat.com>
Date: Feb 10 2026 19:09:13 +0000
Subject: [PATCH 5/9] fix logic; cleanup


---

diff --git a/kojihub/repos.py b/kojihub/repos.py
index cadc433..e02c18c 100644
--- a/kojihub/repos.py
+++ b/kojihub/repos.py
@@ -493,17 +493,20 @@ def do_auto_requests():
     dups = {}
     default_lag = context.opts['RepoAutoLag']
     for tag_id in auto_tags:
-        # choose min_event similar to default_min_event, but different lag
-        # TODO unify code?
+        # make sure we have a sane tag before we make a request
         last = kojihub.tag_last_change_event(tag_id)
         if last is None:
             # shouldn't happen
             # last event cannot be None for a valid tag, but we only queried tag_extra
             logger.error('No last event for tag %i', tag_id)
             continue
+
+        # make the request
         lag = lags.get(tag_id, default_lag)
         check = request_repo(tag_id, priority=5, lag=lag)
         # lower priority so they don't block on-demand
+
+        # stats for debugging
         if check['duplicate']:
             dups[tag_id] = check
         elif check['request']:
@@ -721,6 +724,9 @@ def request_repo(tag, min_event=None, at_event=None, opts=None, priority=None, f
     if lag is not None:
         if min_event is not None or at_event is not None:
             raise koji.ParameterError('The lag option cannot be used with event options')
+        lag = kojihub.convert_value(lag, cast=float)
+        if lag < 0:
+            raise koji.ParameterError('The lag option cannot be negative')
     if at_event is not None:
         if min_event is not None:
             raise koji.ParameterError('The min_event and at_event options conflict')
@@ -788,15 +794,18 @@ def request_repo(tag, min_event=None, at_event=None, opts=None, priority=None, f
 
     # otherwise we make one
     req_id = nextval('repo_queue_id_seq')
+    if min_event is not None:
+        # for a fresh request, always use the last change event
+        min_event = kojihub.tag_last_change_event(taginfo['id'])
+        # TODO - avoid getting last event twice
+        # OR just use getLastEvent?
     data = {
         'id': req_id,
         'owner': context.session.user_id,
         'priority': priority,
         'tag_id': taginfo['id'],
         'at_event': at_event,
-        'min_event': kojihub.tag_last_change_event(taginfo['id']),
-        # TODO - avoid getting last event twice
-        # OR just use getLastEvent?
+        'min_event': min_event,
         'opts': json.dumps(opts),
     }
     insert = InsertProcessor('repo_queue', data=data)

From 564280f28e48bcc6d64af088be4a268c8d716884 Mon Sep 17 00:00:00 2001
From: Mike McLean <mikem@redhat.com>
Date: Feb 10 2026 19:09:13 +0000
Subject: [PATCH 6/9] add some unit tests


---

diff --git a/tests/test_hub/test_repo_requests.py b/tests/test_hub/test_repo_requests.py
index 94fdf28..e3dcbf1 100644
--- a/tests/test_hub/test_repo_requests.py
+++ b/tests/test_hub/test_repo_requests.py
@@ -1101,6 +1101,39 @@ class TestRequestRepo(BaseTest):
         self.InsertProcessor.assert_not_called()
         self.get_repo.assert_not_called()
 
+    def test_lag_invalid(self):
+        self.get_tag.return_value = {'id': 100, 'name': 'TAG', 'extra': {}}
+
+        with self.assertRaises(koji.ParameterError):
+            repos.request_repo('TAGID', lag=-1)
+
+        with self.assertRaises(koji.ParameterError):
+            repos.request_repo('TAGID', lag='invalid value')
+
+        self.InsertProcessor.assert_not_called()
+        self.get_repo.assert_not_called()
+
+    def test_lag_opt(self):
+        self.get_tag.return_value = {'id': 100, 'name': 'TAG', 'extra': {}}
+        self.getLastEvent.return_value = {'id': 101010}
+        last = 100001
+        self.tag_last_change_event.return_value = last
+        self.get_repo.return_value = None
+        self.RepoQueueQuery.return_value.execute.return_value = []
+
+        repos.request_repo('TAGID', lag=0)
+
+        # check all the calls made with the value
+        self.get_repo.assert_called_once()
+        ev = self.get_repo.call_args.kwargs['min_event']
+        self.assertEqual(ev, last)
+        clauses = self.RepoQueueQuery.call_args_list[0].args[0]
+        self.assertIn(['min_event', '>=', last], clauses)
+        self.InsertProcessor.assert_called_once()
+        data = self.InsertProcessor.call_args.kwargs['data']
+        self.assertEqual(data['min_event'], last)
+
+
     def test_lag_conflict(self):
         self.get_tag.return_value = {'id': 100, 'name': 'TAG', 'extra': {}}
 

From c160e472c0ba3e053c3bcb34ac98cc920412e138 Mon Sep 17 00:00:00 2001
From: Mike McLean <mikem@redhat.com>
Date: Feb 10 2026 19:09:13 +0000
Subject: [PATCH 7/9] drop incorrect comment


---

diff --git a/kojihub/repos.py b/kojihub/repos.py
index e02c18c..328b843 100644
--- a/kojihub/repos.py
+++ b/kojihub/repos.py
@@ -798,7 +798,6 @@ def request_repo(tag, min_event=None, at_event=None, opts=None, priority=None, f
         # for a fresh request, always use the last change event
         min_event = kojihub.tag_last_change_event(taginfo['id'])
         # TODO - avoid getting last event twice
-        # OR just use getLastEvent?
     data = {
         'id': req_id,
         'owner': context.session.user_id,

From 114731f911eac824f30a212470dbf8b3a8c7c7d6 Mon Sep 17 00:00:00 2001
From: Mike McLean <mikem@redhat.com>
Date: Feb 10 2026 19:09:13 +0000
Subject: [PATCH 8/9] docs


---

diff --git a/docs/source/repo_generation.rst b/docs/source/repo_generation.rst
index f9beb05..da5102d 100644
--- a/docs/source/repo_generation.rst
+++ b/docs/source/repo_generation.rst
@@ -21,7 +21,7 @@ without a build if configured. They can also be triggered manually.
 
 ::
 
-    repo.request(tag, min_event=None, at_event=None, opts=None, priority=None, force=False)
+    repo.request(tag, min_event=None, at_event=None, opts=None, priority=None, force=False, lag=None)
     description: Request a repo for a tag
 
         :param int|str taginfo: tag id or name
@@ -29,6 +29,7 @@ without a build if configured. They can also be triggered manually.
         :param int at_event: specific event for the repo (optional)
         :param dict opts: custom repo options (optional)
         :param bool force: force request creation, even if a matching repo exists
+        :param int lag: set min_event using a lag value (in seconds)
 
         The special value min_event="last" uses the most recent event for the tag
         Otherwise min_event should be an integer
@@ -38,9 +39,21 @@ without a build if configured. They can also be triggered manually.
         the defaults.
 
 
-Each repo request is for a single tag. The optional ``min_event`` parameter specifies how recent the
-repo needs to be. If not given, Koji chooses a suitably recent event. The optional ``opts`` specifies
-options for creating the repo. If not given, Koji uses the default options based on the tag.
+Each repo request is for a single tag. The optional call parameters govern different aspects of
+repo creation. The call will either report a existing repo that satisfies the parameters,
+report an existing equivalent request entry, or create a new request entry and return that.
+
+Repos can be generated from different points in time.
+The request can ask for a specific event by using the ``at_event`` parameter.
+Otherwise, the call will use a minimum event value.
+The minimum event value can be specified using the optional ``min_event`` parameter, or
+alternately using the ``lag`` parameter.
+If none of these are given, Koji chooses a suitably recent event based on lag settings in the hub.
+See :ref:`repo-lag` below.
+
+The optional ``opts`` specifies options for creating the repo.
+If not given, Koji uses the default options based on the tag.
+See :ref:`repository-options` below.
 
 When the hub responds to this call, it first checks to see if an existing repo satisfies the
 request. If so, then information for that repo is returned and no further action is taken.
@@ -48,6 +61,24 @@ If there is no such repo yet, then Koji records the request and returns the requ
 If an identical active request already exists, then Koji will return that.
 
 
+.. _repo-lag:
+
+Repo lag
+--------
+
+In the default case, a repo request allows of a bit of lag.
+That is, the resulting repo might be a bit older than the current tag state.
+The default lag is controlled by the ``RepoLag`` setting (or ``RepoAutoLag`` for auto regens).
+The lag can be set for individual tags using the ``repo.lag`` tag extra setting,
+and it be overridden by passing the ``lag`` option (or ``min_event``) to the repo.request call.
+
+The purpose of repo lag is to avoid unnecessary regenerations.
+In most cases, a reasonably recent repo is good enough.
+Builds that need more recent repos can pass options that change this.
+
+All lag values are specified in seconds.
+
+
 Build parameters
 ----------------
 
@@ -64,6 +95,8 @@ request mechanism. Instead, the build will wait for these NVRs to be tagged and 
 current repo.
 
 
+.. _repository-options:
+
 Repository Options
 ------------------
 
@@ -240,7 +273,7 @@ When a repo is no longer relevant, Koji will move it to the ``EXPIRED`` state. T
 repo is marked for deletion and should no longer be used.
 
 Once a repo has been expired for a waiting period, Koji will move it to the ``DELETED`` state
-and remove its files from disc. The database entry will remain
+and remove its files from disc. The database entry will remain.
 
 In cases of unusual errors, a repo might be moved to the ``PROBLEM`` state. Such repos should
 not be used and will eventually be deleted.
@@ -274,7 +307,7 @@ RepoAutoLag
     Same as RepoLag, but for automatic requests. Default: ``7200``
 
 RepoLagWindow
-    This affects the granularity of the ``RepoLag`` and ``RepoAutoLag`` settings. Default: ``600``
+    **No longer used**
 
 RepoQueueUser
     The user that should own the ``newRepo`` tasks generated by repo requests. Default: ``kojira``

From 5670c12c1db970010c5d345dcf8e14b1506fcf01 Mon Sep 17 00:00:00 2001
From: Mike McLean <mikem@redhat.com>
Date: Feb 10 2026 19:09:13 +0000
Subject: [PATCH 9/9] drop test refs to RepoLagWindow


---

diff --git a/tests/test_hub/test_repo_requests.py b/tests/test_hub/test_repo_requests.py
index e3dcbf1..3192af6 100644
--- a/tests/test_hub/test_repo_requests.py
+++ b/tests/test_hub/test_repo_requests.py
@@ -42,7 +42,6 @@ class BaseTest(unittest.TestCase):
             'RequestCleanTime': 60 * 24,
             'RepoLag': 3600,
             'RepoAutoLag': 7200,
-            'RepoLagWindow': 600,
             'RepoQueueUser': 'kojira',
             'DebuginfoTags': '',
             'SourceTags': '',
@@ -758,8 +757,6 @@ class TestAutoRequests(BaseTest):
         self.request_repo.assert_called_once_with(99, priority=5, lag=lag)
 
     def test_auto_lag(self):
-        # use a trivial window to simplify the lag calculation
-        self.context.opts['RepoLagWindow'] = 1
         autokeys = [
             {'tag_id': 99, 'key': 'repo.auto', 'value': 'true'},
             {'tag_id': 99, 'key': 'repo.lag', 'value': '0'},
@@ -774,22 +771,6 @@ class TestAutoRequests(BaseTest):
 
         self.request_repo.assert_called_once_with(99, priority=5, lag=0)
 
-    def test_auto_lag_window(self):
-        self.context.opts['RepoLagWindow'] = 600
-        autokeys = [
-            {'tag_id': 99, 'key': 'repo.auto', 'value': 'true'},
-            {'tag_id': 99, 'key': 'repo.lag', 'value': '0'},
-        ]
-        now = 1717171717
-        self.time.return_value = now
-        self.query_execute.return_value = autokeys
-        self.tag_last_change_event.return_value = 1000
-        self.request_repo.return_value = {'repo': None, 'request': 'REQ', 'duplicate': False}
-
-        repos.do_auto_requests()
-
-        self.request_repo.assert_called_once_with(99, priority=5, lag=0)
-
     def test_no_last_tag_event(self):
         # corner case that should not happen
         autokeys = [
@@ -1263,7 +1244,6 @@ class TestDefaultMinEvent(BaseTest):
         now = 1717171717
         self.time.return_value = now
         self.context.opts['RepoLag'] = 3600
-        self.context.opts['RepoLagWindow'] = 1
         taginfo = {'id': 55, 'name': 'MYTAG', 'extra': {}}  # no lag override
         self.tag_last_change_event.return_value = 10000
         self.getLastEvent.return_value = {'id': 9999}
@@ -1280,7 +1260,6 @@ class TestDefaultMinEvent(BaseTest):
         now = 1717171717
         self.time.return_value = now
         self.context.opts['RepoLag'] = 3600
-        self.context.opts['RepoLagWindow'] = 1
         taginfo = {'id': 55, 'name': 'MYTAG', 'extra': {}}  # no lag override
         self.tag_last_change_event.return_value = 9900
         self.getLastEvent.return_value = {'id': 9999}
@@ -1293,31 +1272,10 @@ class TestDefaultMinEvent(BaseTest):
         base_ts = self.getLastEvent.call_args.kwargs['before']
         self.assertEqual(base_ts, now - 3600)
 
-    def test_window(self):
-        now = 1717171717
-        self.time.return_value = now
-        self.context.opts['RepoLag'] = 3600
-        self.context.opts['RepoLagWindow'] = 300
-        taginfo = {'id': 55, 'name': 'MYTAG', 'extra': {}}  # no lag override
-        self.tag_last_change_event.return_value = 9900
-        self.getLastEvent.return_value = {'id': 9999}
-
-        ev = repos.default_min_event(taginfo)
-
-        # we should report the ts for the tag, since it is older
-        self.assertEqual(ev, 9900)
-        self.getLastEvent.assert_called_once()
-        base_ts = self.getLastEvent.call_args.kwargs['before']
-        # should be earlier than target time, but within lag window
-        lag_ts = now - 3600
-        if base_ts > lag_ts or base_ts < lag_ts - 600:
-            raise Exception('Invalid lag window calculation')
-
     def test_lag_override(self):
         now = 1717171717
         self.time.return_value = now
         self.context.opts['RepoLag'] = 3600
-        self.context.opts['RepoLagWindow'] = 1
         taginfo = {'id': 55, 'name': 'MYTAG', 'extra': {'repo.lag': 1800}}
         self.tag_last_change_event.return_value = 10000
         self.getLastEvent.return_value = {'id': 9999}
@@ -1334,7 +1292,6 @@ class TestDefaultMinEvent(BaseTest):
         now = 1717171717
         self.time.return_value = now
         self.context.opts['RepoLag'] = 3600
-        self.context.opts['RepoLagWindow'] = 1
         taginfo = {'id': 55, 'name': 'MYTAG', 'extra': {'repo.lag': 'not an int'}}
         self.tag_last_change_event.return_value = 10000
         self.getLastEvent.return_value = {'id': 9999}

