alissa-tools-github-revloop 0.16.5__tar.gz → 0.16.6__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.
Files changed (32) hide show
  1. {alissa_tools_github_revloop-0.16.5/src/main/alissa_tools_github_revloop.egg-info → alissa_tools_github_revloop-0.16.6}/PKG-INFO +1 -1
  2. {alissa_tools_github_revloop-0.16.5 → alissa_tools_github_revloop-0.16.6}/src/main/alissa/tools/github/revloop/loop.py +47 -23
  3. alissa_tools_github_revloop-0.16.6/src/main/alissa/tools/github/revloop/version +1 -0
  4. {alissa_tools_github_revloop-0.16.5 → alissa_tools_github_revloop-0.16.6/src/main/alissa_tools_github_revloop.egg-info}/PKG-INFO +1 -1
  5. alissa_tools_github_revloop-0.16.5/src/main/alissa/tools/github/revloop/version +0 -1
  6. {alissa_tools_github_revloop-0.16.5 → alissa_tools_github_revloop-0.16.6}/LICENSE +0 -0
  7. {alissa_tools_github_revloop-0.16.5 → alissa_tools_github_revloop-0.16.6}/MANIFEST.in +0 -0
  8. {alissa_tools_github_revloop-0.16.5 → alissa_tools_github_revloop-0.16.6}/NOTICE +0 -0
  9. {alissa_tools_github_revloop-0.16.5 → alissa_tools_github_revloop-0.16.6}/README.md +0 -0
  10. {alissa_tools_github_revloop-0.16.5 → alissa_tools_github_revloop-0.16.6}/requirements.txt +0 -0
  11. {alissa_tools_github_revloop-0.16.5 → alissa_tools_github_revloop-0.16.6}/setup.cfg +0 -0
  12. {alissa_tools_github_revloop-0.16.5 → alissa_tools_github_revloop-0.16.6}/setup.py +0 -0
  13. {alissa_tools_github_revloop-0.16.5 → alissa_tools_github_revloop-0.16.6}/src/main/alissa/tools/github/revloop/__init__.py +0 -0
  14. {alissa_tools_github_revloop-0.16.5 → alissa_tools_github_revloop-0.16.6}/src/main/alissa/tools/github/revloop/__main__.py +0 -0
  15. {alissa_tools_github_revloop-0.16.5 → alissa_tools_github_revloop-0.16.6}/src/main/alissa/tools/github/revloop/alissa.py +0 -0
  16. {alissa_tools_github_revloop-0.16.5 → alissa_tools_github_revloop-0.16.6}/src/main/alissa/tools/github/revloop/config.py +0 -0
  17. {alissa_tools_github_revloop-0.16.5 → alissa_tools_github_revloop-0.16.6}/src/main/alissa/tools/github/revloop/ghclient.py +0 -0
  18. {alissa_tools_github_revloop-0.16.5 → alissa_tools_github_revloop-0.16.6}/src/main/alissa/tools/github/revloop/proc.py +0 -0
  19. {alissa_tools_github_revloop-0.16.5 → alissa_tools_github_revloop-0.16.6}/src/main/alissa/tools/github/revloop/prreview.py +0 -0
  20. {alissa_tools_github_revloop-0.16.5 → alissa_tools_github_revloop-0.16.6}/src/main/alissa/tools/github/revloop/state.py +0 -0
  21. {alissa_tools_github_revloop-0.16.5 → alissa_tools_github_revloop-0.16.6}/src/main/alissa/tools/github/revloop/version.py +0 -0
  22. {alissa_tools_github_revloop-0.16.5 → alissa_tools_github_revloop-0.16.6}/src/main/alissa/tools/github/revloop/webui/__init__.py +0 -0
  23. {alissa_tools_github_revloop-0.16.5 → alissa_tools_github_revloop-0.16.6}/src/main/alissa/tools/github/revloop/webui/__main__.py +0 -0
  24. {alissa_tools_github_revloop-0.16.5 → alissa_tools_github_revloop-0.16.6}/src/main/alissa/tools/github/revloop/webui/auth.py +0 -0
  25. {alissa_tools_github_revloop-0.16.5 → alissa_tools_github_revloop-0.16.6}/src/main/alissa/tools/github/revloop/webui/page.py +0 -0
  26. {alissa_tools_github_revloop-0.16.5 → alissa_tools_github_revloop-0.16.6}/src/main/alissa/tools/github/revloop/webui/server.py +0 -0
  27. {alissa_tools_github_revloop-0.16.5 → alissa_tools_github_revloop-0.16.6}/src/main/alissa/tools/github/revloop/webui/sources.py +0 -0
  28. {alissa_tools_github_revloop-0.16.5 → alissa_tools_github_revloop-0.16.6}/src/main/alissa/tools/github/revloop/webui/sysinfo.py +0 -0
  29. {alissa_tools_github_revloop-0.16.5 → alissa_tools_github_revloop-0.16.6}/src/main/alissa_tools_github_revloop.egg-info/SOURCES.txt +0 -0
  30. {alissa_tools_github_revloop-0.16.5 → alissa_tools_github_revloop-0.16.6}/src/main/alissa_tools_github_revloop.egg-info/dependency_links.txt +0 -0
  31. {alissa_tools_github_revloop-0.16.5 → alissa_tools_github_revloop-0.16.6}/src/main/alissa_tools_github_revloop.egg-info/entry_points.txt +0 -0
  32. {alissa_tools_github_revloop-0.16.5 → alissa_tools_github_revloop-0.16.6}/src/main/alissa_tools_github_revloop.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: alissa-tools-github-revloop
3
- Version: 0.16.5
3
+ Version: 0.16.6
4
4
  Summary: ALISSA-TOOLS-GITHUB-REVLOOP
5
5
  Home-page: https://alissa.app
6
6
  Author: Fahera
@@ -644,6 +644,13 @@ class ReviewWatcher:
644
644
  # The surviving-session set the cap alarm last paged on, so a standing
645
645
  # over-cap condition pages once per episode -- see _check_session_cap.
646
646
  self._paged_cap: frozenset[str] | None = None
647
+ # (repo slug, number, drift kind) already announced by THIS process in
648
+ # dry-run. Deliberately in-memory: a dry-run pass must never be
649
+ # suppressed by anything durable (a production pass writing the ledger
650
+ # would silence the operator's diagnostic), but a daemon left in
651
+ # dry-run should not re-announce the same drift every poll either --
652
+ # see _warn_identity_drift.
653
+ self._dry_run_drift: set[tuple[str, int, str]] = set()
647
654
 
648
655
  # -- per-PR decision ---------------------------------------------------
649
656
 
@@ -1420,11 +1427,12 @@ class ReviewWatcher:
1420
1427
  )
1421
1428
  return
1422
1429
 
1423
- # Above the dry-run guard: the drift check reads, records a ledger row
1424
- # and logs, but takes nothing on GitHub -- it OBSERVES the pass rather
1425
- # than acting in it, the same reasoning that writes poll snapshots in
1426
- # dry-run. Dry-run is also the mode an operator reaches for to diagnose
1427
- # exactly this, so staying silent about it there is the worst place.
1430
+ # Above the dry-run guard: the drift check reads and logs but takes
1431
+ # nothing on GitHub, and in dry-run it records nothing either -- it
1432
+ # OBSERVES the pass rather than acting in it. Dry-run is the mode an
1433
+ # operator reaches for to diagnose exactly this, so staying silent
1434
+ # about it there is the worst place. See _warn_identity_drift for why
1435
+ # the ledger is untouched in BOTH directions there.
1428
1436
  self._warn_identity_drift(pr)
1429
1437
 
1430
1438
  if self.config.dry_run:
@@ -1479,6 +1487,23 @@ class ReviewWatcher:
1479
1487
  pr.slug, mine, why, verdict.url, pr.head_sha[:8], left,
1480
1488
  )
1481
1489
 
1490
+ def _drift_gated(self, pr: PullRequest, kind: str, record: bool) -> bool:
1491
+ """Whether this drift-check gate is already closed for `pr`.
1492
+
1493
+ The two backing stores are not interchangeable and the split is the
1494
+ whole point: durable in production, process-lifetime in dry-run, so
1495
+ neither mode can ever silence the other. See _warn_identity_drift.
1496
+ """
1497
+ if record:
1498
+ return self.state.pinged(pr.full_name, pr.number, kind)
1499
+ return (pr.full_name, pr.number, kind) in self._dry_run_drift
1500
+
1501
+ def _note_drift_gate(self, pr: PullRequest, kind: str, record: bool) -> None:
1502
+ if record:
1503
+ self.state.record_ping(pr.full_name, pr.number, kind)
1504
+ else:
1505
+ self._dry_run_drift.add((pr.full_name, pr.number, kind))
1506
+
1482
1507
  def _warn_identity_drift(self, pr: PullRequest) -> None:
1483
1508
  """Page once when the round's write-up landed under a login GitHub does
1484
1509
  not hold the request against.
@@ -1492,25 +1517,26 @@ class ReviewWatcher:
1492
1517
  Diagnostic only -- it never gates the removal, and an unreadable review
1493
1518
  list just means no warning, not a stalled close-out.
1494
1519
 
1495
- The extra read it needs is bounded to once per (PR, head); see
1496
- drift_probe_kind for why that bound exists at all.
1520
+ Two gates, both of them once-per-condition: the extra read runs once per
1521
+ (PR, head) and the warning once per (PR, login pair). See
1522
+ drift_probe_kind and identity_drift_kind.
1497
1523
 
1498
- In `--dry-run` this touches the ping ledger in NEITHER direction: it
1499
- always probes, always warns, and records nothing. Both halves matter.
1524
+ In `--dry-run` the SAME two gates apply, held in memory instead of in
1525
+ the ping ledger -- which the run must not touch in either direction.
1500
1526
  Writing would let a diagnostic pass durably silence the daemon it was
1501
- run to diagnose -- `state_db` has no dry-run branch, so the rows land in
1502
- the same `state.db` production reads, and the alarm is once-per-PR. And
1503
- reading would silence the DIAGNOSTIC instead: a production pass that
1527
+ run to diagnose (`state_db` has no dry-run branch, so the rows land in
1528
+ the same `state.db` production reads, and the alarm is once-per-PR).
1529
+ Reading would silence the DIAGNOSTIC instead: a production pass that
1504
1530
  already probed this head would make the operator's dry-run print
1505
- nothing. The cost is one review read per dry-run poll, which is the
1506
- right trade -- dry-run withdraws nothing, so the PR stays in the poll
1507
- set regardless, and the probe bound exists to protect the production
1508
- failure loop, not a run an operator is watching.
1531
+ nothing. Process-lifetime scope gives both -- a fresh dry-run always
1532
+ announces, and a daemon left running in dry-run does not re-emit the
1533
+ same block every poll. Same reasoning as `_ignored_acks`: a statement
1534
+ about one process belongs in the process, not in the ledger.
1509
1535
  """
1510
1536
  record = not self.config.dry_run
1511
1537
 
1512
1538
  probe = drift_probe_kind(pr.head_sha)
1513
- if record and self.state.pinged(pr.full_name, pr.number, probe):
1539
+ if self._drift_gated(pr, probe, record):
1514
1540
  return
1515
1541
 
1516
1542
  try:
@@ -1519,8 +1545,7 @@ class ReviewWatcher:
1519
1545
  # Deliberately not recorded: a read that failed settles nothing.
1520
1546
  log.debug("%s: could not read reviews for the drift check: %s", pr.slug, exc)
1521
1547
  return
1522
- if record:
1523
- self.state.record_ping(pr.full_name, pr.number, probe)
1548
+ self._note_drift_gate(pr, probe, record)
1524
1549
 
1525
1550
  substantive = [r for r in reviews if r.is_substantive]
1526
1551
  if not substantive:
@@ -1530,10 +1555,9 @@ class ReviewWatcher:
1530
1555
  return
1531
1556
 
1532
1557
  kind = identity_drift_kind(self.github.login, newest.author)
1533
- if record:
1534
- if self.state.pinged(pr.full_name, pr.number, kind):
1535
- return
1536
- self.state.record_ping(pr.full_name, pr.number, kind)
1558
+ if self._drift_gated(pr, kind, record):
1559
+ return
1560
+ self._note_drift_gate(pr, kind, record)
1537
1561
  log.warning(
1538
1562
  "IDENTITY DRIFT on %s: the review request is held against %r but "
1539
1563
  "the round's newest review was submitted by %r (%s). GitHub only "
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: alissa-tools-github-revloop
3
- Version: 0.16.5
3
+ Version: 0.16.6
4
4
  Summary: ALISSA-TOOLS-GITHUB-REVLOOP
5
5
  Home-page: https://alissa.app
6
6
  Author: Fahera