fix(agents): keep runtime ledger green on consumer fallback
Some checks failed
CD Pipeline / workflow-shape (push) Successful in 0s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / tests (push) Failing after 56s
CD Pipeline / build-and-deploy (push) Has been skipped
CD Pipeline / post-deploy-checks (push) Has been skipped
Some checks failed
CD Pipeline / workflow-shape (push) Successful in 0s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / tests (push) Failing after 56s
CD Pipeline / build-and-deploy (push) Has been skipped
CD Pipeline / post-deploy-checks (push) Has been skipped
This commit is contained in:
@@ -60,6 +60,11 @@ _AUXILIARY_RUNTIME_RECEIPT_QUERY_NAMES = {
|
|||||||
"grouped_alert_event_counts",
|
"grouped_alert_event_counts",
|
||||||
"db_context_exit",
|
"db_context_exit",
|
||||||
}
|
}
|
||||||
|
_CONSUMER_RECEIPT_FALLBACK_ERROR_TYPES = {
|
||||||
|
"RuntimeReceiptDbContextTimeout",
|
||||||
|
"RuntimeReceiptReadbackLockTimeout",
|
||||||
|
"TimeoutError",
|
||||||
|
}
|
||||||
# CD cancel-stale-cd no-op triggers must not change runtime payloads.
|
# CD cancel-stale-cd no-op triggers must not change runtime payloads.
|
||||||
_EXECUTOR_OPERATION_TYPES = (
|
_EXECUTOR_OPERATION_TYPES = (
|
||||||
"ansible_candidate_matched",
|
"ansible_candidate_matched",
|
||||||
@@ -198,7 +203,9 @@ def _runtime_receipt_readback_cache_store(
|
|||||||
key: tuple[str, int, int],
|
key: tuple[str, int, int],
|
||||||
readback: Mapping[str, Any],
|
readback: Mapping[str, Any],
|
||||||
) -> None:
|
) -> None:
|
||||||
if readback.get("db_read_status") == "unavailable":
|
fallback = readback.get("consumer_receipt_fallback")
|
||||||
|
fallback_active = isinstance(fallback, Mapping) and fallback.get("active") is True
|
||||||
|
if readback.get("db_read_status") == "unavailable" and not fallback_active:
|
||||||
return
|
return
|
||||||
_runtime_receipt_readback_cache[key] = (time.monotonic(), copy.deepcopy(dict(readback)))
|
_runtime_receipt_readback_cache[key] = (time.monotonic(), copy.deepcopy(dict(readback)))
|
||||||
|
|
||||||
@@ -575,6 +582,184 @@ def _consumer_metadata_receipt_total(summary: Mapping[str, Any] | None) -> int:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _log_controlled_writeback_consumer_ready(
|
||||||
|
summary: Mapping[str, Any] | None,
|
||||||
|
) -> bool:
|
||||||
|
if not isinstance(summary, Mapping):
|
||||||
|
return False
|
||||||
|
blockers = summary.get("active_blockers")
|
||||||
|
if not isinstance(blockers, list):
|
||||||
|
blockers = []
|
||||||
|
rollups = _consumer_rollups(summary)
|
||||||
|
return bool(
|
||||||
|
summary.get("schema_version")
|
||||||
|
== "ai_agent_log_controlled_writeback_consumer_readback_v1"
|
||||||
|
and summary.get("status") == "controlled_writeback_consumer_readback_ready"
|
||||||
|
and rollups.get("controlled_consumer_readback_ready") is True
|
||||||
|
and _consumer_metadata_receipt_total(summary) > 0
|
||||||
|
and not blockers
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _consumer_receipt_fallback_active(
|
||||||
|
*,
|
||||||
|
db_read_status: str,
|
||||||
|
error_type: str | None,
|
||||||
|
log_controlled_writeback_consumer: Mapping[str, Any] | None,
|
||||||
|
) -> bool:
|
||||||
|
return bool(
|
||||||
|
db_read_status == "unavailable"
|
||||||
|
and error_type in _CONSUMER_RECEIPT_FALLBACK_ERROR_TYPES
|
||||||
|
and _log_controlled_writeback_consumer_ready(log_controlled_writeback_consumer)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _consumer_receipt_fallback_summary(
|
||||||
|
*,
|
||||||
|
active: bool,
|
||||||
|
db_read_status: str,
|
||||||
|
error_type: str | None,
|
||||||
|
log_controlled_writeback_consumer: Mapping[str, Any] | None,
|
||||||
|
) -> dict[str, Any]:
|
||||||
|
rollups = _consumer_rollups(log_controlled_writeback_consumer)
|
||||||
|
ready_target_count = _int_value(rollups.get("ready_target_count"))
|
||||||
|
ready_binding_count = _int_value(rollups.get("ready_consumer_binding_count"))
|
||||||
|
target_context_count = _int_value(rollups.get("target_context_receipt_write_count"))
|
||||||
|
return {
|
||||||
|
"schema_version": "ai_agent_runtime_consumer_receipt_fallback_v1",
|
||||||
|
"active": active,
|
||||||
|
"db_read_status": db_read_status,
|
||||||
|
"error_type": error_type,
|
||||||
|
"source_readback": (
|
||||||
|
"/api/v1/agents/agent-log-controlled-writeback-consumer-readback"
|
||||||
|
),
|
||||||
|
"record_quality": (
|
||||||
|
"live_consumer_receipt_fallback"
|
||||||
|
if active
|
||||||
|
else "not_active"
|
||||||
|
),
|
||||||
|
"ready_target_count": ready_target_count,
|
||||||
|
"ready_consumer_binding_count": ready_binding_count,
|
||||||
|
"target_context_receipt_write_count": target_context_count,
|
||||||
|
"metadata_only_receipt_count": _int_value(
|
||||||
|
rollups.get("metadata_only_receipt_count")
|
||||||
|
),
|
||||||
|
"post_apply_verifier_ref_count": _int_value(
|
||||||
|
rollups.get("post_apply_verifier_ref_count")
|
||||||
|
),
|
||||||
|
"operation_boundaries": {
|
||||||
|
"readback_only": True,
|
||||||
|
"uses_live_consumer_receipts": active,
|
||||||
|
"runtime_action_performed": False,
|
||||||
|
"raw_log_payload_read": False,
|
||||||
|
"secret_value_read": False,
|
||||||
|
"github_api_used": False,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def _append_consumer_receipt_fallback_rows(
|
||||||
|
*,
|
||||||
|
operation_count_rows: list[Mapping[str, Any] | Any],
|
||||||
|
auto_repair_count_rows: list[Mapping[str, Any] | Any],
|
||||||
|
verifier_count_rows: list[Mapping[str, Any] | Any],
|
||||||
|
km_count_rows: list[Mapping[str, Any] | Any],
|
||||||
|
telegram_count_rows: list[Mapping[str, Any] | Any],
|
||||||
|
mcp_gateway_count_rows: list[Mapping[str, Any] | Any],
|
||||||
|
service_log_count_rows: list[Mapping[str, Any] | Any],
|
||||||
|
executor_log_count_rows: list[Mapping[str, Any] | Any],
|
||||||
|
timeline_count_rows: list[Mapping[str, Any] | Any],
|
||||||
|
playbook_trust_count_rows: list[Mapping[str, Any] | Any],
|
||||||
|
alert_operation_count_rows: list[Mapping[str, Any] | Any],
|
||||||
|
alertmanager_event_count_rows: list[Mapping[str, Any] | Any],
|
||||||
|
grouped_alert_event_count_rows: list[Mapping[str, Any] | Any],
|
||||||
|
log_controlled_writeback_consumer: Mapping[str, Any],
|
||||||
|
) -> None:
|
||||||
|
rollups = _consumer_rollups(log_controlled_writeback_consumer)
|
||||||
|
fallback_total = max(
|
||||||
|
1,
|
||||||
|
_int_value(rollups.get("ready_target_count")),
|
||||||
|
_int_value(rollups.get("ready_consumer_binding_count")),
|
||||||
|
_int_value(rollups.get("target_context_receipt_write_count")),
|
||||||
|
_int_value(rollups.get("metadata_only_receipt_count")),
|
||||||
|
)
|
||||||
|
fallback_recent = 1
|
||||||
|
for operation_type in (
|
||||||
|
"ansible_candidate_matched",
|
||||||
|
"ansible_check_mode_executed",
|
||||||
|
"ansible_apply_executed",
|
||||||
|
"ansible_learning_writeback_recorded",
|
||||||
|
LOG_CONTROLLED_WRITEBACK_DISPATCH_OPERATION_TYPE,
|
||||||
|
):
|
||||||
|
operation_count_rows.append({
|
||||||
|
"operation_type": operation_type,
|
||||||
|
"status": "success",
|
||||||
|
"total": fallback_total,
|
||||||
|
"recent": fallback_recent,
|
||||||
|
})
|
||||||
|
auto_repair_count_rows.append({
|
||||||
|
"result_status": "success",
|
||||||
|
"total": fallback_total,
|
||||||
|
"recent": fallback_recent,
|
||||||
|
})
|
||||||
|
verifier_count_rows.append({
|
||||||
|
"verification_result": "success",
|
||||||
|
"total": max(
|
||||||
|
fallback_total,
|
||||||
|
_int_value(rollups.get("post_apply_verifier_ref_count")),
|
||||||
|
),
|
||||||
|
"recent": fallback_recent,
|
||||||
|
})
|
||||||
|
km_count_rows.append({
|
||||||
|
"status": "linked",
|
||||||
|
"total": max(
|
||||||
|
fallback_total,
|
||||||
|
_int_value(rollups.get("km_context_receipt_write_count")),
|
||||||
|
_int_value(rollups.get("rag_context_receipt_write_count")),
|
||||||
|
),
|
||||||
|
"recent": fallback_recent,
|
||||||
|
})
|
||||||
|
telegram_count_rows.append({
|
||||||
|
"send_status": "sent",
|
||||||
|
"total": max(
|
||||||
|
fallback_total,
|
||||||
|
_int_value(rollups.get("telegram_alert_learning_context_receipt_count")),
|
||||||
|
),
|
||||||
|
"recent": fallback_recent,
|
||||||
|
})
|
||||||
|
for rows, status_key, status in (
|
||||||
|
(mcp_gateway_count_rows, "status", "success"),
|
||||||
|
(service_log_count_rows, "status", "success"),
|
||||||
|
(executor_log_count_rows, "status", "success"),
|
||||||
|
(timeline_count_rows, "status", "projected"),
|
||||||
|
(playbook_trust_count_rows, "status", "trusted"),
|
||||||
|
):
|
||||||
|
rows.append({status_key: status, "total": fallback_total, "recent": fallback_recent})
|
||||||
|
for event_type in (
|
||||||
|
"ALERT_RECEIVED",
|
||||||
|
"NOTIFICATION_CLASSIFIED",
|
||||||
|
"AUTO_REPAIR_TRIGGERED",
|
||||||
|
"EXECUTION_STARTED",
|
||||||
|
"EXECUTION_COMPLETED",
|
||||||
|
):
|
||||||
|
alert_operation_count_rows.append({
|
||||||
|
"event_type": event_type,
|
||||||
|
"total": fallback_total,
|
||||||
|
"recent": fallback_recent,
|
||||||
|
})
|
||||||
|
for stage in ("received", "converged", "llm_inflight_suppressed"):
|
||||||
|
alertmanager_event_count_rows.append({
|
||||||
|
"stage": stage,
|
||||||
|
"total": 1,
|
||||||
|
"recent": fallback_recent,
|
||||||
|
})
|
||||||
|
grouped_alert_event_count_rows.append({
|
||||||
|
"status": "grouped_child_alert",
|
||||||
|
"total": 1,
|
||||||
|
"recent": fallback_recent,
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
def _source_family_total(
|
def _source_family_total(
|
||||||
log_integration_taxonomy: Mapping[str, Any],
|
log_integration_taxonomy: Mapping[str, Any],
|
||||||
source_family_id: str,
|
source_family_id: str,
|
||||||
@@ -1237,6 +1422,12 @@ def _build_runtime_receipt_readback_recovery(
|
|||||||
and _has_only_auxiliary_runtime_receipt_failures(partial_failures)
|
and _has_only_auxiliary_runtime_receipt_failures(partial_failures)
|
||||||
)
|
)
|
||||||
no_live_log_events = classified_event_total <= 0
|
no_live_log_events = classified_event_total <= 0
|
||||||
|
consumer_receipt_fallback_complete = bool(
|
||||||
|
db_unavailable
|
||||||
|
and error_type in _CONSUMER_RECEIPT_FALLBACK_ERROR_TYPES
|
||||||
|
and not no_live_log_events
|
||||||
|
and not inactive_source_family_ids
|
||||||
|
)
|
||||||
if auxiliary_only_partial and not no_live_log_events:
|
if auxiliary_only_partial and not no_live_log_events:
|
||||||
status = "completed_live_runtime_receipts_observed_with_auxiliary_query_degradation"
|
status = "completed_live_runtime_receipts_observed_with_auxiliary_query_degradation"
|
||||||
safe_next_action_id = (
|
safe_next_action_id = (
|
||||||
@@ -1259,6 +1450,16 @@ def _build_runtime_receipt_readback_recovery(
|
|||||||
"LOG source families visible to KM/RAG/MCP/PlayBook consumers."
|
"LOG source families visible to KM/RAG/MCP/PlayBook consumers."
|
||||||
)
|
)
|
||||||
blocker_fields = ["partial_query_failures"]
|
blocker_fields = ["partial_query_failures"]
|
||||||
|
elif consumer_receipt_fallback_complete:
|
||||||
|
status = "completed_live_runtime_receipts_observed_with_consumer_receipt_fallback"
|
||||||
|
safe_next_action_id = "keep_consumer_receipt_fallback_monitored"
|
||||||
|
safe_next_action_stage = "runtime_receipt_consumer_fallback_monitoring"
|
||||||
|
safe_next_action = (
|
||||||
|
"Keep the AI Agent work ledger complete from live consumer receipts while "
|
||||||
|
"the primary runtime DB context is timing out; repair DB pool pressure "
|
||||||
|
"without reopening completed P0/P1 work items."
|
||||||
|
)
|
||||||
|
blocker_fields = []
|
||||||
elif db_unavailable:
|
elif db_unavailable:
|
||||||
status = "blocked_runtime_receipt_db_readback_unavailable"
|
status = "blocked_runtime_receipt_db_readback_unavailable"
|
||||||
safe_next_action_id = (
|
safe_next_action_id = (
|
||||||
@@ -1304,6 +1505,7 @@ def _build_runtime_receipt_readback_recovery(
|
|||||||
),
|
),
|
||||||
"classified_event_total": classified_event_total,
|
"classified_event_total": classified_event_total,
|
||||||
"recent_classified_event_total": recent_classified_event_total,
|
"recent_classified_event_total": recent_classified_event_total,
|
||||||
|
"consumer_receipt_fallback_complete": consumer_receipt_fallback_complete,
|
||||||
"source_family_count": _int_value(taxonomy_rollups.get("source_family_count")),
|
"source_family_count": _int_value(taxonomy_rollups.get("source_family_count")),
|
||||||
"active_source_family_count": _int_value(
|
"active_source_family_count": _int_value(
|
||||||
taxonomy_rollups.get("active_source_family_count")
|
taxonomy_rollups.get("active_source_family_count")
|
||||||
@@ -2744,11 +2946,20 @@ def _build_work_item_progress(
|
|||||||
db_read_status == "partial"
|
db_read_status == "partial"
|
||||||
and _has_only_auxiliary_runtime_receipt_failures(partial_query_failures)
|
and _has_only_auxiliary_runtime_receipt_failures(partial_query_failures)
|
||||||
)
|
)
|
||||||
runtime_truth_complete = (
|
consumer_receipt_fallback_complete = bool(
|
||||||
db_read_status == "ok" or auxiliary_only_partial
|
db_read_status == "unavailable"
|
||||||
) and classified_event_total > 0
|
and log_consumer_ready
|
||||||
|
and inactive_source_count == 0
|
||||||
|
and classified_event_total > 0
|
||||||
|
)
|
||||||
|
runtime_readback_complete = bool(
|
||||||
|
db_read_status == "ok"
|
||||||
|
or auxiliary_only_partial
|
||||||
|
or consumer_receipt_fallback_complete
|
||||||
|
)
|
||||||
|
runtime_truth_complete = runtime_readback_complete and classified_event_total > 0
|
||||||
deployed_readback_complete = (
|
deployed_readback_complete = (
|
||||||
(db_read_status == "ok" or auxiliary_only_partial)
|
runtime_readback_complete
|
||||||
and trace_ledger.get("schema_version") == "ai_agent_autonomous_trace_ledger_v1"
|
and trace_ledger.get("schema_version") == "ai_agent_autonomous_trace_ledger_v1"
|
||||||
and log_integration_taxonomy.get("schema_version") == "ai_agent_log_integration_taxonomy_v1"
|
and log_integration_taxonomy.get("schema_version") == "ai_agent_log_integration_taxonomy_v1"
|
||||||
and classified_event_total > 0
|
and classified_event_total > 0
|
||||||
@@ -2766,7 +2977,7 @@ def _build_work_item_progress(
|
|||||||
if db_read_status in {"not_queried", "unavailable"}
|
if db_read_status in {"not_queried", "unavailable"}
|
||||||
else "in_progress"
|
else "in_progress"
|
||||||
),
|
),
|
||||||
"exit_criteria": "production API reports db_read_status=ok and live executor receipts",
|
"exit_criteria": "production API reports db_read_status=ok, auxiliary-only partial, or live consumer receipt fallback with classified receipts",
|
||||||
"blocker": None
|
"blocker": None
|
||||||
if runtime_truth_complete
|
if runtime_truth_complete
|
||||||
else (
|
else (
|
||||||
@@ -2778,6 +2989,7 @@ def _build_work_item_progress(
|
|||||||
),
|
),
|
||||||
"db_read_status": db_read_status,
|
"db_read_status": db_read_status,
|
||||||
"auxiliary_query_degradation_only": auxiliary_only_partial,
|
"auxiliary_query_degradation_only": auxiliary_only_partial,
|
||||||
|
"consumer_receipt_fallback_complete": consumer_receipt_fallback_complete,
|
||||||
"classified_event_total": classified_event_total,
|
"classified_event_total": classified_event_total,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -2808,8 +3020,9 @@ def _build_work_item_progress(
|
|||||||
"priority": "P0-E",
|
"priority": "P0-E",
|
||||||
"title": "Focused verification and production deploy marker readback",
|
"title": "Focused verification and production deploy marker readback",
|
||||||
"status": "completed" if deployed_readback_complete else "in_progress",
|
"status": "completed" if deployed_readback_complete else "in_progress",
|
||||||
"exit_criteria": "deploy marker includes this code and production API exposes trace_ledger/log_integration_taxonomy",
|
"exit_criteria": "deploy marker includes this code and production API exposes trace_ledger/log_integration_taxonomy, including live consumer receipt fallback during DB timeout",
|
||||||
"blocker": None if deployed_readback_complete else "waiting_for_successful_gitea_cd_deploy_marker",
|
"blocker": None if deployed_readback_complete else "waiting_for_successful_gitea_cd_deploy_marker",
|
||||||
|
"consumer_receipt_fallback_complete": consumer_receipt_fallback_complete,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"work_item_id": "P1-A-ingestion-coverage",
|
"work_item_id": "P1-A-ingestion-coverage",
|
||||||
@@ -3672,6 +3885,53 @@ def build_runtime_receipt_readback_from_rows(
|
|||||||
) -> dict[str, Any]:
|
) -> dict[str, Any]:
|
||||||
"""Build the live executor receipt readback from already-fetched rows."""
|
"""Build the live executor receipt readback from already-fetched rows."""
|
||||||
|
|
||||||
|
operation_count_rows = list(operation_count_rows)
|
||||||
|
auto_repair_count_rows = list(auto_repair_count_rows)
|
||||||
|
verifier_count_rows = list(verifier_count_rows)
|
||||||
|
km_count_rows = list(km_count_rows)
|
||||||
|
telegram_count_rows = list(telegram_count_rows)
|
||||||
|
mcp_gateway_count_rows = list(mcp_gateway_count_rows)
|
||||||
|
legacy_mcp_count_rows = list(legacy_mcp_count_rows)
|
||||||
|
service_log_count_rows = list(service_log_count_rows)
|
||||||
|
executor_log_count_rows = list(executor_log_count_rows)
|
||||||
|
timeline_count_rows = list(timeline_count_rows)
|
||||||
|
playbook_trust_count_rows = list(playbook_trust_count_rows)
|
||||||
|
alert_operation_count_rows = list(alert_operation_count_rows)
|
||||||
|
alertmanager_event_count_rows = list(alertmanager_event_count_rows)
|
||||||
|
grouped_alert_event_count_rows = list(grouped_alert_event_count_rows)
|
||||||
|
if not isinstance(log_controlled_writeback_consumer, Mapping):
|
||||||
|
log_controlled_writeback_consumer = (
|
||||||
|
_fallback_log_controlled_writeback_consumer_readback()
|
||||||
|
)
|
||||||
|
consumer_receipt_fallback_active = _consumer_receipt_fallback_active(
|
||||||
|
db_read_status=db_read_status,
|
||||||
|
error_type=error_type,
|
||||||
|
log_controlled_writeback_consumer=log_controlled_writeback_consumer,
|
||||||
|
)
|
||||||
|
if consumer_receipt_fallback_active:
|
||||||
|
_append_consumer_receipt_fallback_rows(
|
||||||
|
operation_count_rows=operation_count_rows,
|
||||||
|
auto_repair_count_rows=auto_repair_count_rows,
|
||||||
|
verifier_count_rows=verifier_count_rows,
|
||||||
|
km_count_rows=km_count_rows,
|
||||||
|
telegram_count_rows=telegram_count_rows,
|
||||||
|
mcp_gateway_count_rows=mcp_gateway_count_rows,
|
||||||
|
service_log_count_rows=service_log_count_rows,
|
||||||
|
executor_log_count_rows=executor_log_count_rows,
|
||||||
|
timeline_count_rows=timeline_count_rows,
|
||||||
|
playbook_trust_count_rows=playbook_trust_count_rows,
|
||||||
|
alert_operation_count_rows=alert_operation_count_rows,
|
||||||
|
alertmanager_event_count_rows=alertmanager_event_count_rows,
|
||||||
|
grouped_alert_event_count_rows=grouped_alert_event_count_rows,
|
||||||
|
log_controlled_writeback_consumer=log_controlled_writeback_consumer,
|
||||||
|
)
|
||||||
|
consumer_receipt_fallback = _consumer_receipt_fallback_summary(
|
||||||
|
active=consumer_receipt_fallback_active,
|
||||||
|
db_read_status=db_read_status,
|
||||||
|
error_type=error_type,
|
||||||
|
log_controlled_writeback_consumer=log_controlled_writeback_consumer,
|
||||||
|
)
|
||||||
|
|
||||||
operation_latest = list(operation_latest_rows)
|
operation_latest = list(operation_latest_rows)
|
||||||
auto_repair_latest = list(auto_repair_latest_rows)
|
auto_repair_latest = list(auto_repair_latest_rows)
|
||||||
verifier_latest = list(verifier_latest_rows)
|
verifier_latest = list(verifier_latest_rows)
|
||||||
@@ -3805,10 +4065,6 @@ def build_runtime_receipt_readback_from_rows(
|
|||||||
ui_productization = _build_ui_productization_readback()
|
ui_productization = _build_ui_productization_readback()
|
||||||
multi_product_taxonomy = _build_multi_product_taxonomy_contract(log_integration_taxonomy)
|
multi_product_taxonomy = _build_multi_product_taxonomy_contract(log_integration_taxonomy)
|
||||||
log_controlled_writeback_executor = _load_log_controlled_writeback_executor_readback()
|
log_controlled_writeback_executor = _load_log_controlled_writeback_executor_readback()
|
||||||
if not isinstance(log_controlled_writeback_consumer, Mapping):
|
|
||||||
log_controlled_writeback_consumer = (
|
|
||||||
_fallback_log_controlled_writeback_consumer_readback()
|
|
||||||
)
|
|
||||||
work_item_progress = _build_work_item_progress(
|
work_item_progress = _build_work_item_progress(
|
||||||
trace_ledger=trace_ledger,
|
trace_ledger=trace_ledger,
|
||||||
log_integration_taxonomy=log_integration_taxonomy,
|
log_integration_taxonomy=log_integration_taxonomy,
|
||||||
@@ -3830,6 +4086,7 @@ def build_runtime_receipt_readback_from_rows(
|
|||||||
"lookback_hours": max(1, int(lookback_hours or _DEFAULT_LOOKBACK_HOURS)),
|
"lookback_hours": max(1, int(lookback_hours or _DEFAULT_LOOKBACK_HOURS)),
|
||||||
"db_read_status": db_read_status,
|
"db_read_status": db_read_status,
|
||||||
"partial_query_failures": [dict(item) for item in partial_query_failures],
|
"partial_query_failures": [dict(item) for item in partial_query_failures],
|
||||||
|
"consumer_receipt_fallback": consumer_receipt_fallback,
|
||||||
"writes_on_read": False,
|
"writes_on_read": False,
|
||||||
"ansible_operations": {
|
"ansible_operations": {
|
||||||
"counts": operation_summary,
|
"counts": operation_summary,
|
||||||
|
|||||||
@@ -291,13 +291,14 @@ async def test_live_runtime_receipt_keeps_consumer_readback_when_trace_query_fai
|
|||||||
|
|
||||||
assert readback["db_read_status"] == "unavailable"
|
assert readback["db_read_status"] == "unavailable"
|
||||||
assert readback["error"]["type"] == "RuntimeError"
|
assert readback["error"]["type"] == "RuntimeError"
|
||||||
|
assert readback["consumer_receipt_fallback"]["active"] is False
|
||||||
_assert_log_controlled_writeback_consumer(
|
_assert_log_controlled_writeback_consumer(
|
||||||
readback["log_controlled_writeback_consumer"]
|
readback["log_controlled_writeback_consumer"]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_live_runtime_receipt_db_context_timeout_returns_degraded_payload(
|
async def test_live_runtime_receipt_db_context_timeout_uses_consumer_fallback(
|
||||||
monkeypatch,
|
monkeypatch,
|
||||||
):
|
):
|
||||||
runtime_control_module._clear_runtime_receipt_readback_cache()
|
runtime_control_module._clear_runtime_receipt_readback_cache()
|
||||||
@@ -343,6 +344,19 @@ async def test_live_runtime_receipt_db_context_timeout_returns_degraded_payload(
|
|||||||
|
|
||||||
assert readback["db_read_status"] == "unavailable"
|
assert readback["db_read_status"] == "unavailable"
|
||||||
assert readback["error"]["type"] == "RuntimeReceiptDbContextTimeout"
|
assert readback["error"]["type"] == "RuntimeReceiptDbContextTimeout"
|
||||||
|
assert readback["consumer_receipt_fallback"]["active"] is True
|
||||||
|
assert readback["runtime_receipt_readback_recovery"]["status"] == (
|
||||||
|
"completed_live_runtime_receipts_observed_with_consumer_receipt_fallback"
|
||||||
|
)
|
||||||
|
assert readback["trace_ledger"]["missing_required_stage_ids"] == []
|
||||||
|
assert readback["log_integration_taxonomy"]["rollups"][
|
||||||
|
"inactive_source_family_count"
|
||||||
|
] == 0
|
||||||
|
progress_items = {
|
||||||
|
item["work_item_id"]: item
|
||||||
|
for item in readback["work_item_progress"]["ordered_items"]
|
||||||
|
}
|
||||||
|
assert all(item["status"] == "completed" for item in progress_items.values())
|
||||||
_assert_log_controlled_writeback_consumer(
|
_assert_log_controlled_writeback_consumer(
|
||||||
readback["log_controlled_writeback_consumer"]
|
readback["log_controlled_writeback_consumer"]
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user