fix: close unconfirmed displays superseded by confirmed updates
Community checks / verify (push) Skipped
Verify Frame Flow / verify (push) Successful in 6m29s

This commit is contained in:
渡口浪人
2026-10-18 19:27:35 +08:00
parent dec17aeb1d
commit cb8ac32b74
11 changed files with 129 additions and 26 deletions
+46
View File
@@ -1,8 +1,10 @@
"""Durable, read-only recovery progress for writes with uncertain outcomes."""
import json
from datetime import UTC, datetime
from uuid import uuid4
from pigway_frame_flow.errors import ErrorCode
from pigway_frame_flow.storage.database import encode, now_iso
@@ -71,3 +73,47 @@ class RecoveryMonitor:
if row:
row["requires_manual_review"] = row["state"] == "manual_review"
return row
def close_superseded_displays(self):
for op in self.db.all(
"SELECT * FROM operations WHERE action='display' AND write_started=1 "
"AND status IN ('SYNCING','UNKNOWN')"
):
result = json.loads(op["result"] or "{}")
if not result.get("image_id") or json.loads(op["payload"]).get(
"options", {}
).get("restore_previous"):
continue
newer = self.db.one(
"SELECT id,result FROM operations WHERE device_id=? AND action='display' "
"AND status='COMPLETED' AND write_started=1 AND created_at>? "
"AND COALESCE(json_extract(payload,'$.options.restore_previous'),0)=0 "
"AND json_extract(result,'$.image_id') IS NOT NULL "
"ORDER BY created_at DESC LIMIT 1",
(op["device_id"], op["created_at"]),
)
if (
not newer
or json.loads(newer["result"])["image_id"] == result["image_id"]
):
continue
# A later confirmed permanent display ends this attempt, but cannot
# prove whether the earlier image was ever shown. Never replay it.
self.service.update(
op["id"],
"FAILED",
error={
"code": ErrorCode.DISPLAY_NOT_CONFIRMED,
"message": "Superseded by a later confirmed display; earlier display unconfirmed",
"request_id": op["request_id"],
"details": {
"superseded_by_operation_id": newer["id"],
"previous_error": json.loads(op["error"] or "null"),
},
},
)
self.db.history(op, "DISPLAY_NOT_CONFIRMED")
self.db.event(
"operation.failed",
{"operation_id": op["id"], "code": ErrorCode.DISPLAY_NOT_CONFIRMED},
)
+2
View File
@@ -884,6 +884,8 @@ class DisplayService:
except FlowError:
pass
self.recovery.close_superseded_displays()
def expire(self):
if not self.settings.mock and not self.settings.write_enabled:
return