Automatically resume empty saved source reviews
This commit is contained in:
1 parent
cd362b3b81
commit
976a4fa7b2
11 files changed
+585
-29
No files matched your search
+51
-24
@@ -31,6 +31,7 @@ VERSION = "arr-source-field-review/v1"
|
||||
REANALYSIS_POLICY = "oracle-optional-association/v1"
|
||||
REANALYSIS_VERSION = "arr-source-reanalysis/v1"
|
||||
STATUS_POLICY = "arr-exclude-cancelled/v1"
|
||||
EMPTY_REVIEW_ACTOR = "system:arr-empty-source-review"
|
||||
LIMIT = 100 * 1024 * 1024
|
||||
OPTIONAL = frozenset({"BLOCK_CODE", "RES_COMMENT", "PRODUCTS", "ROOM_CATEGORY_LABEL"})
|
||||
LABELS = {
|
||||
@@ -381,9 +382,11 @@ class DataFieldReviews:
|
||||
require(fingerprint(actual) == fingerprint(meta), "data_review_prepare_conflict")
|
||||
review = self._public(directory, actual, original, state)
|
||||
# A complete ordinary source needs no human step or derived source.
|
||||
# A reanalysis remains an explicit review until finalized, even if
|
||||
# its validated source interpretation resolves every listed gap.
|
||||
return review if review["total_count"] or "source_reanalysis" in state or "reservation_status_evidence" in state else None
|
||||
# Validated overlays still need a frozen derived source. The
|
||||
# executor may finish a genuinely empty review under a system actor.
|
||||
return review if (review["total_count"] or state["decisions"] or state["status"] == "finalized"
|
||||
or "source_reanalysis" in state or "reservation_status_evidence" in state
|
||||
or (directory / "finalize-intent.json").exists()) else None
|
||||
|
||||
def get(self, request_id):
|
||||
directory = self._directory(request_id)
|
||||
@@ -583,33 +586,57 @@ class DataFieldReviews:
|
||||
return json_bytes(data), binding
|
||||
|
||||
def finalize(self, request_id, revision, actor):
|
||||
directory = self._directory(request_id)
|
||||
with self._lock(directory):
|
||||
meta, original, state = self._read(directory)
|
||||
return self._finalize_locked(directory, meta, original, state, revision, actor)
|
||||
|
||||
def recover_ready(self, request_id):
|
||||
"""Freeze validated zero-item saved reviews, or replay a verified prior freeze.
|
||||
|
||||
This internal recovery operation has no HTTP route. A completed manual
|
||||
list is deliberately not empty: its explicit human confirmation remains
|
||||
required. Read/derive/guard/freeze share the same revision lock.
|
||||
"""
|
||||
directory = self._directory(request_id)
|
||||
with self._lock(directory):
|
||||
meta, original, state = self._read(directory)
|
||||
if state["status"] == "finalized":
|
||||
self._verify_frozen(directory, meta, original, state)
|
||||
return self._public(directory, meta, original, state)
|
||||
self._revision(state, revision)
|
||||
actor = self._actor(actor)
|
||||
if self._issues(directory, self._derive(directory, original, state)):
|
||||
raise _error("INCOMPLETE", "请先完善并确认所有异常字段", 409)
|
||||
intent = directory / "finalize-intent.json"
|
||||
prior_sha256 = fingerprint(state)
|
||||
if intent.exists():
|
||||
frozen = strict_json(protected_read(intent, LIMIT))
|
||||
require(frozen["prior_sha256"] == prior_sha256, "data_review_finalize_context_changed")
|
||||
state = frozen["state"]
|
||||
else:
|
||||
state["revision"] += 1
|
||||
state["status"] = "finalized"
|
||||
state["events"].append({"revision": state["revision"], "action": "finalize", "actor": actor,
|
||||
"at": datetime.now(timezone.utc).isoformat()})
|
||||
atomic_json(intent, {"prior_sha256": prior_sha256, "state": state}, replace=False)
|
||||
payload, binding = self._frozen(directory, meta, original, state)
|
||||
_write_once(directory / "reviewed-source.json", payload)
|
||||
state["derived_sha256"], state["binding_manifest_sha256"] = _hash(payload), binding
|
||||
self._publish(directory, state)
|
||||
return True
|
||||
if original.get("status") not in {"collected", "collected_with_gaps"}:
|
||||
return False
|
||||
review = self._public(directory, meta, original, state)
|
||||
if review["total_count"] != 0 or review["pending_count"] != 0 or not review["can_finalize"]:
|
||||
return False
|
||||
self._finalize_locked(directory, meta, original, state, state["revision"], EMPTY_REVIEW_ACTOR)
|
||||
return True
|
||||
|
||||
def _finalize_locked(self, directory, meta, original, state, revision, actor):
|
||||
if state["status"] == "finalized":
|
||||
self._verify_frozen(directory, meta, original, state)
|
||||
return self._public(directory, meta, original, state)
|
||||
self._revision(state, revision)
|
||||
actor = self._actor(actor)
|
||||
if self._issues(directory, self._derive(directory, original, state)):
|
||||
raise _error("INCOMPLETE", "请先完善并确认所有异常字段", 409)
|
||||
intent = directory / "finalize-intent.json"
|
||||
prior_sha256 = fingerprint(state)
|
||||
if intent.exists():
|
||||
frozen = strict_json(protected_read(intent, LIMIT))
|
||||
require(frozen["prior_sha256"] == prior_sha256, "data_review_finalize_context_changed")
|
||||
state = frozen["state"]
|
||||
else:
|
||||
state["revision"] += 1
|
||||
state["status"] = "finalized"
|
||||
state["events"].append({"revision": state["revision"], "action": "finalize", "actor": actor,
|
||||
"at": datetime.now(timezone.utc).isoformat()})
|
||||
atomic_json(intent, {"prior_sha256": prior_sha256, "state": state}, replace=False)
|
||||
payload, binding = self._frozen(directory, meta, original, state)
|
||||
_write_once(directory / "reviewed-source.json", payload)
|
||||
state["derived_sha256"], state["binding_manifest_sha256"] = _hash(payload), binding
|
||||
self._publish(directory, state)
|
||||
return self._public(directory, meta, original, state)
|
||||
|
||||
def _verify_frozen(self, directory, meta, original, state):
|
||||
payload, binding = self._frozen(directory, meta, original, state)
|
||||
|
||||
Reference in new issue
Block a user