alissa-tools-github-revloop 0.31.17__tar.gz → 0.31.18__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {alissa_tools_github_revloop-0.31.17/src/main/alissa_tools_github_revloop.egg-info → alissa_tools_github_revloop-0.31.18}/PKG-INFO +1 -1
- {alissa_tools_github_revloop-0.31.17 → alissa_tools_github_revloop-0.31.18}/src/main/alissa/tools/github/revloop/loop.py +67 -34
- {alissa_tools_github_revloop-0.31.17 → alissa_tools_github_revloop-0.31.18}/src/main/alissa/tools/github/revloop/parking.py +3 -1
- {alissa_tools_github_revloop-0.31.17 → alissa_tools_github_revloop-0.31.18}/src/main/alissa/tools/github/revloop/state.py +6 -3
- alissa_tools_github_revloop-0.31.18/src/main/alissa/tools/github/revloop/version +1 -0
- {alissa_tools_github_revloop-0.31.17 → alissa_tools_github_revloop-0.31.18}/src/main/alissa/tools/github/revloop/webui/server.py +3 -1
- {alissa_tools_github_revloop-0.31.17 → alissa_tools_github_revloop-0.31.18/src/main/alissa_tools_github_revloop.egg-info}/PKG-INFO +1 -1
- alissa_tools_github_revloop-0.31.17/src/main/alissa/tools/github/revloop/version +0 -1
- {alissa_tools_github_revloop-0.31.17 → alissa_tools_github_revloop-0.31.18}/LICENSE +0 -0
- {alissa_tools_github_revloop-0.31.17 → alissa_tools_github_revloop-0.31.18}/MANIFEST.in +0 -0
- {alissa_tools_github_revloop-0.31.17 → alissa_tools_github_revloop-0.31.18}/NOTICE +0 -0
- {alissa_tools_github_revloop-0.31.17 → alissa_tools_github_revloop-0.31.18}/README.md +0 -0
- {alissa_tools_github_revloop-0.31.17 → alissa_tools_github_revloop-0.31.18}/requirements.txt +0 -0
- {alissa_tools_github_revloop-0.31.17 → alissa_tools_github_revloop-0.31.18}/setup.cfg +0 -0
- {alissa_tools_github_revloop-0.31.17 → alissa_tools_github_revloop-0.31.18}/setup.py +0 -0
- {alissa_tools_github_revloop-0.31.17 → alissa_tools_github_revloop-0.31.18}/src/main/alissa/tools/github/revloop/__init__.py +0 -0
- {alissa_tools_github_revloop-0.31.17 → alissa_tools_github_revloop-0.31.18}/src/main/alissa/tools/github/revloop/__main__.py +0 -0
- {alissa_tools_github_revloop-0.31.17 → alissa_tools_github_revloop-0.31.18}/src/main/alissa/tools/github/revloop/alissa.py +0 -0
- {alissa_tools_github_revloop-0.31.17 → alissa_tools_github_revloop-0.31.18}/src/main/alissa/tools/github/revloop/alissa_client.py +0 -0
- {alissa_tools_github_revloop-0.31.17 → alissa_tools_github_revloop-0.31.18}/src/main/alissa/tools/github/revloop/bows.py +0 -0
- {alissa_tools_github_revloop-0.31.17 → alissa_tools_github_revloop-0.31.18}/src/main/alissa/tools/github/revloop/config.py +0 -0
- {alissa_tools_github_revloop-0.31.17 → alissa_tools_github_revloop-0.31.18}/src/main/alissa/tools/github/revloop/fleet_vitals.py +0 -0
- {alissa_tools_github_revloop-0.31.17 → alissa_tools_github_revloop-0.31.18}/src/main/alissa/tools/github/revloop/ghclient.py +0 -0
- {alissa_tools_github_revloop-0.31.17 → alissa_tools_github_revloop-0.31.18}/src/main/alissa/tools/github/revloop/janitor.py +0 -0
- {alissa_tools_github_revloop-0.31.17 → alissa_tools_github_revloop-0.31.18}/src/main/alissa/tools/github/revloop/loop_events.py +0 -0
- {alissa_tools_github_revloop-0.31.17 → alissa_tools_github_revloop-0.31.18}/src/main/alissa/tools/github/revloop/proc.py +0 -0
- {alissa_tools_github_revloop-0.31.17 → alissa_tools_github_revloop-0.31.18}/src/main/alissa/tools/github/revloop/prompts.py +0 -0
- {alissa_tools_github_revloop-0.31.17 → alissa_tools_github_revloop-0.31.18}/src/main/alissa/tools/github/revloop/prreview.py +0 -0
- {alissa_tools_github_revloop-0.31.17 → alissa_tools_github_revloop-0.31.18}/src/main/alissa/tools/github/revloop/trust.py +0 -0
- {alissa_tools_github_revloop-0.31.17 → alissa_tools_github_revloop-0.31.18}/src/main/alissa/tools/github/revloop/version.py +0 -0
- {alissa_tools_github_revloop-0.31.17 → alissa_tools_github_revloop-0.31.18}/src/main/alissa/tools/github/revloop/webui/__init__.py +0 -0
- {alissa_tools_github_revloop-0.31.17 → alissa_tools_github_revloop-0.31.18}/src/main/alissa/tools/github/revloop/webui/__main__.py +0 -0
- {alissa_tools_github_revloop-0.31.17 → alissa_tools_github_revloop-0.31.18}/src/main/alissa/tools/github/revloop/webui/auth.py +0 -0
- {alissa_tools_github_revloop-0.31.17 → alissa_tools_github_revloop-0.31.18}/src/main/alissa/tools/github/revloop/webui/page.py +0 -0
- {alissa_tools_github_revloop-0.31.17 → alissa_tools_github_revloop-0.31.18}/src/main/alissa/tools/github/revloop/webui/sources.py +0 -0
- {alissa_tools_github_revloop-0.31.17 → alissa_tools_github_revloop-0.31.18}/src/main/alissa/tools/github/revloop/webui/sysinfo.py +0 -0
- {alissa_tools_github_revloop-0.31.17 → alissa_tools_github_revloop-0.31.18}/src/main/alissa_tools_github_revloop.egg-info/SOURCES.txt +0 -0
- {alissa_tools_github_revloop-0.31.17 → alissa_tools_github_revloop-0.31.18}/src/main/alissa_tools_github_revloop.egg-info/dependency_links.txt +0 -0
- {alissa_tools_github_revloop-0.31.17 → alissa_tools_github_revloop-0.31.18}/src/main/alissa_tools_github_revloop.egg-info/entry_points.txt +0 -0
- {alissa_tools_github_revloop-0.31.17 → alissa_tools_github_revloop-0.31.18}/src/main/alissa_tools_github_revloop.egg-info/top_level.txt +0 -0
|
@@ -6302,20 +6302,49 @@ class ReviewWatcher:
|
|
|
6302
6302
|
#157): claim the spawn of this round's session against the drain
|
|
6303
6303
|
flag, run `spawn` under the claim, and drop the claim however it ends.
|
|
6304
6304
|
|
|
6305
|
-
The gate sits ABOVE every side effect of the spawn -- the
|
|
6306
|
-
|
|
6307
|
-
activity line --
|
|
6308
|
-
|
|
6309
|
-
|
|
6310
|
-
|
|
6311
|
-
|
|
6305
|
+
The gate sits ABOVE every side effect of the spawn but one -- the
|
|
6306
|
+
`alissa tmux queue add`, the census bump, the ledger row and the
|
|
6307
|
+
activity line all come after it -- and a round it stands down stays
|
|
6308
|
+
owed: a QUEUED `drained` decision writes no spawn row, burns no round
|
|
6309
|
+
number and spends no attempt, exactly like the slot gate. The claim
|
|
6310
|
+
and the flag are read and written in one immediate transaction on
|
|
6311
|
+
each side (`State.claim_spawn` / `State.set_drain`): a drain that
|
|
6312
6312
|
lands while this spawn is between its gate and its ledger write sees
|
|
6313
|
-
the claim and refuses itself
|
|
6314
|
-
|
|
6315
|
-
|
|
6313
|
+
the claim and refuses itself. A ledger that cannot answer stands the
|
|
6314
|
+
spawn down too -- a spawn that cannot prove the seat is not drained
|
|
6315
|
+
does not happen.
|
|
6316
|
+
|
|
6317
|
+
The claim only counts for `parking.SPAWN_CLAIM_TTL`, and the hub add
|
|
6318
|
+
(`_ensure_hub`, a clone on a PR's first round) can outlast it. So
|
|
6319
|
+
`_spawn_claimed` re-takes the claim (`_claim_spawn` again, issue
|
|
6320
|
+
#173) between the hub add and the enqueue, which refreshes it and
|
|
6321
|
+
re-reads the flag: a drain that held while the hub was provisioned
|
|
6322
|
+
stands the round down there, the same QUEUED `drained` way. That late
|
|
6323
|
+
re-check is the one stand-down that happens AFTER a side effect --
|
|
6324
|
+
the hub is provisioned and stays -- which is harmless, because the
|
|
6325
|
+
hub is a reusable cache the round's next spawn finds in place.
|
|
6326
|
+
Together the two claims mean a park can never race a spawn, whatever
|
|
6327
|
+
the drain's freshness rule allows.
|
|
6316
6328
|
|
|
6317
6329
|
Dry-run READS the flag and claims nothing: it shares the production
|
|
6318
6330
|
state path, and a dry pass must write no durable row."""
|
|
6331
|
+
refused = self._claim_spawn(pr, round_, name)
|
|
6332
|
+
if refused is not None:
|
|
6333
|
+
return refused
|
|
6334
|
+
try:
|
|
6335
|
+
return spawn()
|
|
6336
|
+
finally:
|
|
6337
|
+
if not self.config.dry_run:
|
|
6338
|
+
self.state.release_spawn(name)
|
|
6339
|
+
|
|
6340
|
+
def _claim_spawn(
|
|
6341
|
+
self, pr: PullRequest, round_: int, name: str, *, late: bool = False,
|
|
6342
|
+
) -> "Decision | None":
|
|
6343
|
+
"""Claim (or, `late`, re-claim) the spawn of `name` against the drain
|
|
6344
|
+
flag: None when the spawn may proceed, else the QUEUED `drained`
|
|
6345
|
+
decision that stands the round down. Dry-run reads the flag and
|
|
6346
|
+
claims nothing. See `_drain_gated`."""
|
|
6347
|
+
where = " after its hub was provisioned" if late else ""
|
|
6319
6348
|
try:
|
|
6320
6349
|
if self.config.dry_run:
|
|
6321
6350
|
drain = self.state.drain()
|
|
@@ -6323,36 +6352,32 @@ class ReviewWatcher:
|
|
|
6323
6352
|
drain = self.state.claim_spawn(name)
|
|
6324
6353
|
except sqlite3.Error as exc:
|
|
6325
6354
|
log.warning(
|
|
6326
|
-
"%s round %d: could not claim the spawn against the drain flag "
|
|
6327
|
-
"(%s) — standing it down this pass", pr.slug, round_, exc,
|
|
6328
|
-
)
|
|
6329
|
-
return Decision(
|
|
6330
|
-
Action.QUEUED,
|
|
6331
|
-
f"round {round_} stood down — the state ledger could not prove "
|
|
6332
|
-
f"the seat is not drained ({exc}); retrying next poll",
|
|
6333
|
-
round_,
|
|
6334
|
-
drained=True,
|
|
6335
|
-
)
|
|
6336
|
-
if drain is not None:
|
|
6337
|
-
since = parking_mod.iso(drain["drained_at"])
|
|
6338
|
-
until = parking_mod.iso(drain["expires_at"])
|
|
6339
|
-
log.info(
|
|
6340
|
-
"%s round %d: not spawning — the seat is drained for parking "
|
|
6341
|
-
"since %s (until %s)", pr.slug, round_, since, until,
|
|
6355
|
+
"%s round %d: could not claim the spawn against the drain flag%s "
|
|
6356
|
+
"(%s) — standing it down this pass", pr.slug, round_, where, exc,
|
|
6342
6357
|
)
|
|
6343
6358
|
return Decision(
|
|
6344
6359
|
Action.QUEUED,
|
|
6345
|
-
f"round {round_}
|
|
6346
|
-
f"
|
|
6347
|
-
f"retrying once it is undrained",
|
|
6360
|
+
f"round {round_} stood down{where} — the state ledger could not "
|
|
6361
|
+
f"prove the seat is not drained ({exc}); retrying next poll",
|
|
6348
6362
|
round_,
|
|
6349
6363
|
drained=True,
|
|
6350
6364
|
)
|
|
6351
|
-
|
|
6352
|
-
return
|
|
6353
|
-
|
|
6354
|
-
|
|
6355
|
-
|
|
6365
|
+
if drain is None:
|
|
6366
|
+
return None
|
|
6367
|
+
since = parking_mod.iso(drain["drained_at"])
|
|
6368
|
+
until = parking_mod.iso(drain["expires_at"])
|
|
6369
|
+
log.info(
|
|
6370
|
+
"%s round %d: not spawning%s — the seat is drained for parking "
|
|
6371
|
+
"since %s (until %s)", pr.slug, round_, where, since, until,
|
|
6372
|
+
)
|
|
6373
|
+
return Decision(
|
|
6374
|
+
Action.QUEUED,
|
|
6375
|
+
f"round {round_} held{where} — the seat is drained for parking since "
|
|
6376
|
+
f"{since} (until {until}: {drain['reason'] or 'no reason given'}); "
|
|
6377
|
+
f"retrying once it is undrained",
|
|
6378
|
+
round_,
|
|
6379
|
+
drained=True,
|
|
6380
|
+
)
|
|
6356
6381
|
|
|
6357
6382
|
def _spawn_claimed(
|
|
6358
6383
|
self,
|
|
@@ -6427,6 +6452,14 @@ class ReviewWatcher:
|
|
|
6427
6452
|
# provisioned -- unknown, never settled.
|
|
6428
6453
|
return Decision(Action.SKIPPED, problem, round_, owed=True)
|
|
6429
6454
|
|
|
6455
|
+
# The hub add can outlast the gate's claim (a clone on a PR's first
|
|
6456
|
+
# round): re-take it, refreshing it and re-reading the drain flag, so
|
|
6457
|
+
# a drain that landed meanwhile stands the round down here (issue
|
|
6458
|
+
# #173). The claim is still released in `_drain_gated`'s finally.
|
|
6459
|
+
refused = self._claim_spawn(pr, round_, name, late=True)
|
|
6460
|
+
if refused is not None:
|
|
6461
|
+
return refused
|
|
6462
|
+
|
|
6430
6463
|
self.alissa.enqueue_reviewer(
|
|
6431
6464
|
session=name,
|
|
6432
6465
|
directive=directive,
|
|
@@ -26,7 +26,9 @@ handshake):
|
|
|
26
26
|
reads every null as a refusal.
|
|
27
27
|
* **The drain.** A flag with a TTL in `state.db` (`State.set_drain`), cleared
|
|
28
28
|
when the daemon boots. While it holds, the round spawn stands down before
|
|
29
|
-
its first side effect (`ReviewWatcher._drain_gated`)
|
|
29
|
+
its first side effect (`ReviewWatcher._drain_gated`), or, when the drain
|
|
30
|
+
lands while the hub is provisioned, after the hub add and before the
|
|
31
|
+
enqueue (the post-hub re-claim).
|
|
30
32
|
"""
|
|
31
33
|
|
|
32
34
|
from __future__ import annotations
|
|
@@ -39,6 +39,8 @@ from collections.abc import Callable, Iterable
|
|
|
39
39
|
from dataclasses import dataclass
|
|
40
40
|
from pathlib import Path
|
|
41
41
|
|
|
42
|
+
from .parking import SPAWN_CLAIM_TTL
|
|
43
|
+
|
|
42
44
|
log = logging.getLogger(__name__)
|
|
43
45
|
|
|
44
46
|
# Poll-snapshot retention: the newest N rows are kept, older ones pruned on
|
|
@@ -2067,11 +2069,12 @@ class State:
|
|
|
2067
2069
|
|
|
2068
2070
|
def set_drain(
|
|
2069
2071
|
self, ttl: int, reason: str, now: "float | None" = None,
|
|
2070
|
-
claim_ttl: int =
|
|
2072
|
+
claim_ttl: int = SPAWN_CLAIM_TTL,
|
|
2071
2073
|
) -> "tuple[dict, list[dict]]":
|
|
2072
2074
|
"""Raise the drain flag for `ttl` seconds and return it with the spawn
|
|
2073
|
-
claims standing at that instant (younger than `claim_ttl
|
|
2074
|
-
one is a spawn whose process
|
|
2075
|
+
claims standing at that instant (younger than `claim_ttl`, by default
|
|
2076
|
+
`parking.SPAWN_CLAIM_TTL` -- an older one is a spawn whose process
|
|
2077
|
+
died mid-way, cleared at the next boot).
|
|
2075
2078
|
ONE immediate transaction, so a spawn either claimed before this (and
|
|
2076
2079
|
is in the list) or claims after it (and sees the flag). A drain that
|
|
2077
2080
|
is already up is replaced: a re-drain restarts the TTL. Raises
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0.31.18
|
|
@@ -332,7 +332,9 @@ class App:
|
|
|
332
332
|
cleared = self.sources.clear_drain()
|
|
333
333
|
except sqlite3.Error as exc:
|
|
334
334
|
self._audit("undrain", {"ok": False, "error": str(exc)})
|
|
335
|
-
|
|
335
|
+
# The flag's state is unknown here, and unknown is never a value
|
|
336
|
+
# (D2): the 503 already says the undrain did not land.
|
|
337
|
+
return 503, {"drained": None, "error": "state_unavailable"}
|
|
336
338
|
self._audit("undrain", {"ok": True, "cleared": cleared})
|
|
337
339
|
return 200, {"drained": False, "cleared": cleared}
|
|
338
340
|
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
0.31.17
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{alissa_tools_github_revloop-0.31.17 → alissa_tools_github_revloop-0.31.18}/requirements.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|