fix(agent): keep verified closures moving
All checks were successful
CD Pipeline / workflow-shape (push) Successful in 1s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / tests (push) Successful in 2m33s
AWOOOI Harbor 110 Local Repair / workflow-shape (push) Successful in 0s
AWOOOI Harbor 110 Local Repair / harbor-110-local-repair (push) Successful in 15s
CD Pipeline / build-and-deploy (push) Successful in 5m49s
CD Pipeline / post-deploy-checks (push) Successful in 1m54s

This commit is contained in:
ogt
2026-07-11 19:14:48 +08:00
parent e7f2e629d6
commit a0ba1890ad
2 changed files with 107 additions and 8 deletions

View File

@@ -3805,13 +3805,11 @@ async def backfill_missing_auto_repair_execution_receipts_once(
projection.get("verified") or 0
)
projection_error = str(projection.get("error") or "")[:500]
if stats["retry_terminal_projection_scanned"] or projection_error:
stats["scanned"] = stats["retry_terminal_projection_scanned"]
stats["incident_closure_written"] = stats[
"retry_terminal_projection_written"
]
stats["error"] = projection_error or None
return stats
stats["scanned"] = stats["retry_terminal_projection_scanned"]
stats["incident_closure_written"] = stats[
"retry_terminal_projection_written"
]
stats["error"] = projection_error or None
async with get_db_context(project_id) as db:
await db.execute(text("SET LOCAL statement_timeout = '5000ms'"))
result = await db.execute(
@@ -3965,7 +3963,7 @@ async def backfill_missing_auto_repair_execution_receipts_once(
},
)
rows = [dict(row) for row in result.mappings().all()]
stats["scanned"] = len(rows)
stats["scanned"] += len(rows)
for row in rows:
reconstructed = _claim_from_apply_operation_row(row)
if reconstructed is None:

View File

@@ -880,6 +880,107 @@ async def test_retry_terminal_projection_backfill_writes_and_verifies_no_apply(
telegram_readback.assert_awaited_once()
@pytest.mark.asyncio
async def test_retry_projection_does_not_starve_verified_success_closure(
monkeypatch: pytest.MonkeyPatch,
) -> None:
class _RowsResult(_MappingResult):
def __init__(self, rows: list[dict]) -> None:
super().__init__()
self._rows = rows
def all(self) -> list[dict]:
return self._rows
apply_row = {
"op_id": "00000000-0000-0000-0000-000000000104",
"status": "success",
"verifier_ready": True,
}
db = _SequenceDB(_MappingResult(), _RowsResult([apply_row]))
@asynccontextmanager
async def fake_db_context(_project_id: str):
yield db
monkeypatch.setattr(service, "get_db_context", fake_db_context)
monkeypatch.setattr(
service,
"backfill_missing_retry_terminal_projections_once",
AsyncMock(
return_value={
"scanned": 1,
"written": 0,
"retry_receipt_written": 0,
"telegram_receipt_acknowledged": 1,
"incident_receipt_written": 0,
"lifecycle_written": 0,
"verified": 0,
"runtime_apply_executed": False,
"error": None,
}
),
)
monkeypatch.setattr(
service,
"_claim_from_apply_operation_row",
lambda _row: (_claim(), _verified_result()),
)
monkeypatch.setattr(
service,
"_record_post_apply_verifier_and_learning",
AsyncMock(
return_value={
"verification": True,
"verification_passed": True,
"verification_result": "success",
"learning": True,
"trust_learning": True,
"rag_writeback": True,
"runtime_stage_receipts": [],
}
),
)
monkeypatch.setattr(
service,
"_record_auto_repair_execution_receipt",
AsyncMock(return_value=True),
)
monkeypatch.setattr(
service,
"_record_timeline_projection_receipt",
AsyncMock(return_value=None),
)
monkeypatch.setattr(
service,
"_record_runtime_stage_receipts",
AsyncMock(return_value=True),
)
closure = AsyncMock(
return_value={
"status": "controlled_apply_closed",
"closed": True,
"telegram_receipt_acknowledged": True,
"runtime_apply_executed": False,
}
)
monkeypatch.setattr(
service,
"_reconcile_verified_apply_closure_projections",
closure,
)
result = await service.backfill_missing_auto_repair_execution_receipts_once(
limit=1
)
assert result["retry_terminal_projection_scanned"] == 1
assert result["scanned"] == 2
assert result["incident_closure_written"] == 1
assert result["telegram_receipt_acknowledged"] == 1
closure.assert_awaited_once()
@pytest.mark.asyncio
async def test_broker_prioritizes_retry_terminal_projection_backfill(
monkeypatch: pytest.MonkeyPatch,