fix(review): refuse a default choice the saver anchor contradicts (#390)

Apply re-resolves a default item with the file's name: when its saver
anchors the branch, no candidate is offered and the choice is refused.
The scan's anchor check skips bytes carrying a decision and remembers
unanchored file states per process, so a rescan does not inspect an
unchanged file again.
This commit is contained in:
Vito Sansevero
2026-10-27 18:35:45 -07:00
parent c8b1630e1d
commit 3660ff3ecf
5 changed files with 109 additions and 21 deletions
+36 -8
View File
@@ -216,11 +216,31 @@ class ReviewRecordingMixin:
Its current bytes' pending, undecided items then leave the queue
(counted in ``review["untraced"]``: nothing to choose). A failure is
logged and counted, and the file is queued as before.
logged and counted, and the file is queued as before. A file state
(size, ``mtime_ns``, item version) found unanchored in this process
is not inspected again, and bytes carrying a decision are not
inspected at all (a decision is never settled).
"""
located = self._review_location(media_file, roots)
if canonical is None or located is None:
return False
locator = os.path.normcase(located[3])
try:
if not review_capture.saver_anchored(canonical, media_file.name):
return False
facts = os.lstat(located[3])
except OSError:
return False # gone: the capture decides as before
if self.db.review_decided_at(locator, facts.st_size, facts.st_mtime_ns):
return False
version = review_capture.inspection_review_version(canonical)
if version is None:
return False
state = _digest(f"anchor:{facts.st_size}:{facts.st_mtime_ns}:{version}")
memory = self._unanchored_memory()
key = _memory_key(locator)
if memory.get(key) == state:
return False
try:
anchored = review_capture.saver_anchored(canonical, media_file.name)
except Exception:
self.logger.warning(
f"{media_file.name} could not be inspected for Needs review",
@@ -229,14 +249,16 @@ class ReviewRecordingMixin:
if review is not None:
review["errors"] += 1
return False
located = self._review_location(media_file, roots)
if located is None:
return True
if not anchored:
memory.pop(key, None) # re-inserted last: the newest state
memory[key] = state
while len(memory) > MAX_UNTRACED_MEMORY:
del memory[next(iter(memory))]
return False
try:
facts = os.lstat(located[3])
# No version is current for these bytes: any pending item goes.
removed = self.db.settle_stale_review_items(
os.path.normcase(located[3]), facts.st_size, facts.st_mtime_ns, ()
locator, facts.st_size, facts.st_mtime_ns, ()
)
except Exception:
self.logger.warning(
@@ -250,6 +272,12 @@ class ReviewRecordingMixin:
review["untraced"] += removed
return True
def _unanchored_memory(self):
memory = getattr(self, "_unanchored_inspections", None)
if memory is None:
memory = self._unanchored_inspections = {}
return memory
def _settle_stale_reviews(self, media_file, roots, canonical, review=None):
"""Remove the pending, undecided items of an untraced file's current
bytes recorded under another version (best effort, counted in