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:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user