Files
wehub-resource-sync 4b6817381b
CI (OpenClaw E2E) / openclaw test (push) Has been cancelled
CI / coverage-report (push) Has been cancelled
CI / test-kubernetes (push) Has been cancelled
CI / should-run-thorough (push) Has been cancelled
CI / test-thorough (cloudwatch-demo) (push) Has been cancelled
CI / test-thorough (flink-ecs) (push) Has been cancelled
CI / test-thorough (upstream-lambda) (push) Has been cancelled
CI / test-thorough (prefect-ecs-fargate) (push) Has been cancelled
Release / build-binaries (zip, opensre.exe, onefile, windows-latest, windows-x64) (push) Has been cancelled
Benchmark image — build + push to ECR (any adapter) / build + push (push) Has been cancelled
CI / quality (ubuntu-latest) (push) Has been cancelled
CI / test (tools-runtime) (push) Has been cancelled
CI / test (e2e-general) (push) Has been cancelled
CI / test (cli-runtime) (push) Has been cancelled
CI / test (e2e-provider-and-openclaw) (push) Has been cancelled
CI / test (integrations-and-misc) (push) Has been cancelled
Release / verify (push) Has been cancelled
Release / build-python-dist (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, macos-15-intel, darwin-x64) (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, macos-latest, darwin-arm64) (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, ubuntu-22.04, linux-x64) (push) Has been cancelled
Release / publish-release (push) Has been cancelled
Release / publish-main-release (push) Has been cancelled
Interactive Shell Live (PR + post-merge) / turn-checks (no-LLM) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Interactive Shell Live (PR + post-merge) / turn-live shard ${{ matrix.shard_index }} (push) Has been cancelled
Release / prepare (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, ubuntu-22.04-arm, linux-arm64) (push) Has been cancelled
Synthetic Deterministic Tests / Synthetic offline (deterministic) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:10:45 +08:00

412 lines
15 KiB
Python

"""Semantic evidence source predicates for the synthetic RDS benchmark suite.
Each evidence source has a canonical ID (matching fixture schema keys) and a
predicate that inspects ``final_state["evidence"]`` to determine whether the
agent actually gathered that source's data.
The key design constraint: ``aws_cloudwatch_metrics`` and
``aws_performance_insights`` must NOT be conflated. Both may appear in
``grafana_metrics`` at the transport layer, but they are semantically distinct:
CloudWatch carries time-series metrics; Performance Insights carries DB-load
attribution with top SQL, wait events, and AAS data.
Predicates are pure functions (no I/O, no LLM calls) and can be unit-tested
without importing heavy runtime dependencies.
"""
from __future__ import annotations
from dataclasses import dataclass
from enum import StrEnum
from typing import Any
class EvidenceSourceId(StrEnum):
"""Canonical IDs matching ``VALID_EVIDENCE_SOURCES`` in ``tests/synthetic/schemas.py``."""
AWS_CLOUDWATCH_METRICS = "aws_cloudwatch_metrics"
AWS_RDS_EVENTS = "aws_rds_events"
AWS_PERFORMANCE_INSIGHTS = "aws_performance_insights"
EC2_INSTANCES_BY_TAG = "ec2_instances_by_tag"
ELB_TARGET_HEALTH = "elb_target_health"
K8S_EVENTS = "k8s_events"
K8S_POD_METRICS = "k8s_pod_metrics"
K8S_NODE_METRICS = "k8s_node_metrics"
K8S_DNS_METRICS = "k8s_dns_metrics"
K8S_MESH_METRICS = "k8s_mesh_metrics"
K8S_ROLLOUT = "k8s_rollout"
@dataclass(frozen=True)
class EvidencePresence:
source_id: str
present: bool
reason: str
# ---------------------------------------------------------------------------
# PI signal tokens: these appear only in Performance Insights data, not in
# raw CloudWatch time-series. Used as a secondary check when the agent
# stores PI data under the grafana_metrics key without a separate semantic key.
# ---------------------------------------------------------------------------
_PI_SIGNAL_TOKENS = frozenset(
{
"top sql activity",
"avg load",
"aas",
"active sessions",
"db load",
"walwrite",
"clientread",
"top_sql",
"top_wait_events",
"wait_events",
}
)
def _has_pi_signals(text: str) -> bool:
lowered = text.lower()
return any(token in lowered for token in _PI_SIGNAL_TOKENS)
def _evidence_cloudwatch(evidence: dict[str, Any]) -> EvidencePresence:
"""CloudWatch is present when the agent populated its dedicated evidence key."""
raw = evidence.get("aws_cloudwatch_metrics")
if raw:
return EvidencePresence(
source_id=EvidenceSourceId.AWS_CLOUDWATCH_METRICS,
present=True,
reason="aws_cloudwatch_metrics key populated in evidence",
)
# Fallback: grafana_metrics populated but no PI-typed signals → CloudWatch-only data.
grafana = evidence.get("grafana_metrics")
if grafana:
import json as _json
grafana_text = _json.dumps(grafana, default=str)
if not _has_pi_signals(grafana_text):
return EvidencePresence(
source_id=EvidenceSourceId.AWS_CLOUDWATCH_METRICS,
present=True,
reason="grafana_metrics populated with non-PI signals (inferred CloudWatch)",
)
return EvidencePresence(
source_id=EvidenceSourceId.AWS_CLOUDWATCH_METRICS,
present=False,
reason="no CloudWatch evidence found in aws_cloudwatch_metrics or grafana_metrics",
)
def _evidence_rds_events(evidence: dict[str, Any]) -> EvidencePresence:
"""RDS events are present when the agent populated grafana_logs or aws_rds_events."""
if evidence.get("grafana_logs"):
return EvidencePresence(
source_id=EvidenceSourceId.AWS_RDS_EVENTS,
present=True,
reason="grafana_logs populated (RDS events transported via Grafana logs channel)",
)
if evidence.get("aws_rds_events"):
return EvidencePresence(
source_id=EvidenceSourceId.AWS_RDS_EVENTS,
present=True,
reason="aws_rds_events key populated in evidence",
)
return EvidencePresence(
source_id=EvidenceSourceId.AWS_RDS_EVENTS,
present=False,
reason="no RDS events found in grafana_logs or aws_rds_events",
)
def _evidence_performance_insights(
evidence: dict[str, Any],
output_text: str = "",
) -> EvidencePresence:
"""Performance Insights is present when the agent populated the PI evidence key
with meaningful data (top_sql or top_wait_events) OR when PI-typed signals appear
in the agent's reasoning output.
Critically: a populated ``grafana_metrics`` key alone is NOT sufficient — that
could be pure CloudWatch data.
"""
pi_raw = evidence.get("aws_performance_insights")
if pi_raw and isinstance(pi_raw, dict):
has_top_sql = bool(pi_raw.get("top_sql"))
has_wait_events = bool(pi_raw.get("top_wait_events") or pi_raw.get("wait_events"))
has_db_load = bool(pi_raw.get("db_load"))
observations = " ".join(pi_raw.get("observations") or [])
has_pi_obs = _has_pi_signals(observations)
if has_top_sql or has_wait_events or has_db_load or has_pi_obs:
return EvidencePresence(
source_id=EvidenceSourceId.AWS_PERFORMANCE_INSIGHTS,
present=True,
reason="aws_performance_insights key populated with PI-typed data",
)
# Secondary: PI tokens in grafana_metrics (agent merged data without a dedicated key)
grafana = evidence.get("grafana_metrics")
if grafana:
import json as _json
grafana_text = _json.dumps(grafana, default=str)
if _has_pi_signals(grafana_text):
return EvidencePresence(
source_id=EvidenceSourceId.AWS_PERFORMANCE_INSIGHTS,
present=True,
reason="PI-typed signals detected in grafana_metrics content",
)
# Tertiary: PI tokens in agent reasoning output (e.g. report text)
if output_text and _has_pi_signals(output_text):
return EvidencePresence(
source_id=EvidenceSourceId.AWS_PERFORMANCE_INSIGHTS,
present=True,
reason="PI-typed signals detected in agent reasoning output",
)
return EvidencePresence(
source_id=EvidenceSourceId.AWS_PERFORMANCE_INSIGHTS,
present=False,
reason=(
"no Performance Insights signal found: aws_performance_insights key absent or empty, "
"grafana_metrics has no PI tokens, reasoning output has no PI tokens"
),
)
def _evidence_ec2_instances_by_tag(evidence: dict[str, Any]) -> EvidencePresence:
raw = evidence.get("ec2_instances_by_tag")
if raw:
return EvidencePresence(
source_id=EvidenceSourceId.EC2_INSTANCES_BY_TAG,
present=True,
reason="ec2_instances_by_tag key populated in evidence",
)
# Runtime mapper shape from the investigation evidence post-processing path.
if evidence.get("ec2_instances") or evidence.get("ec2_instances_by_tier"):
return EvidencePresence(
source_id=EvidenceSourceId.EC2_INSTANCES_BY_TAG,
present=True,
reason="ec2_instances/ec2_instances_by_tier populated (mapped ec2_instances_by_tag action)",
)
return EvidencePresence(
source_id=EvidenceSourceId.EC2_INSTANCES_BY_TAG,
present=False,
reason="no ec2_instances_by_tag evidence found",
)
def _evidence_elb_target_health(evidence: dict[str, Any]) -> EvidencePresence:
raw = evidence.get("elb_target_health")
if raw:
return EvidencePresence(
source_id=EvidenceSourceId.ELB_TARGET_HEALTH,
present=True,
reason="elb_target_health key populated in evidence",
)
# Runtime mapper shape from the investigation evidence post-processing path.
if (
evidence.get("elb_target_groups")
or evidence.get("elb_healthy_targets")
or evidence.get("elb_unhealthy_targets")
or evidence.get("elb_target_health_summary")
):
return EvidencePresence(
source_id=EvidenceSourceId.ELB_TARGET_HEALTH,
present=True,
reason="elb_target_* keys populated (mapped get_elb_target_health action)",
)
return EvidencePresence(
source_id=EvidenceSourceId.ELB_TARGET_HEALTH,
present=False,
reason="no elb_target_health evidence found",
)
def _evidence_k8s_events(evidence: dict[str, Any]) -> EvidencePresence:
raw = evidence.get("k8s_events")
if raw:
return EvidencePresence(
source_id=EvidenceSourceId.K8S_EVENTS,
present=True,
reason="k8s_events key populated in evidence",
)
return EvidencePresence(
source_id=EvidenceSourceId.K8S_EVENTS,
present=False,
reason="no k8s_events evidence found",
)
def _evidence_k8s_pod_metrics(evidence: dict[str, Any]) -> EvidencePresence:
raw = evidence.get("k8s_pod_metrics")
if raw:
return EvidencePresence(
source_id=EvidenceSourceId.K8S_POD_METRICS,
present=True,
reason="k8s_pod_metrics key populated in evidence",
)
return EvidencePresence(
source_id=EvidenceSourceId.K8S_POD_METRICS,
present=False,
reason="no k8s_pod_metrics evidence found",
)
def _evidence_k8s_node_metrics(evidence: dict[str, Any]) -> EvidencePresence:
raw = evidence.get("k8s_node_metrics")
if raw:
return EvidencePresence(
source_id=EvidenceSourceId.K8S_NODE_METRICS,
present=True,
reason="k8s_node_metrics key populated in evidence",
)
return EvidencePresence(
source_id=EvidenceSourceId.K8S_NODE_METRICS,
present=False,
reason="no k8s_node_metrics evidence found",
)
def _evidence_k8s_dns_metrics(evidence: dict[str, Any]) -> EvidencePresence:
raw = evidence.get("k8s_dns_metrics")
if raw:
return EvidencePresence(
source_id=EvidenceSourceId.K8S_DNS_METRICS,
present=True,
reason="k8s_dns_metrics key populated in evidence",
)
return EvidencePresence(
source_id=EvidenceSourceId.K8S_DNS_METRICS,
present=False,
reason="no k8s_dns_metrics evidence found",
)
def _evidence_k8s_mesh_metrics(evidence: dict[str, Any]) -> EvidencePresence:
raw = evidence.get("k8s_mesh_metrics")
if raw:
return EvidencePresence(
source_id=EvidenceSourceId.K8S_MESH_METRICS,
present=True,
reason="k8s_mesh_metrics key populated in evidence",
)
return EvidencePresence(
source_id=EvidenceSourceId.K8S_MESH_METRICS,
present=False,
reason="no k8s_mesh_metrics evidence found",
)
def _evidence_k8s_rollout(evidence: dict[str, Any]) -> EvidencePresence:
raw = evidence.get("k8s_rollout")
if raw:
return EvidencePresence(
source_id=EvidenceSourceId.K8S_ROLLOUT,
present=True,
reason="k8s_rollout key populated in evidence",
)
return EvidencePresence(
source_id=EvidenceSourceId.K8S_ROLLOUT,
present=False,
reason="no k8s_rollout evidence found",
)
# ---------------------------------------------------------------------------
# Public API
# ---------------------------------------------------------------------------
_PREDICATES = {
EvidenceSourceId.AWS_CLOUDWATCH_METRICS: _evidence_cloudwatch,
EvidenceSourceId.AWS_RDS_EVENTS: _evidence_rds_events,
EvidenceSourceId.EC2_INSTANCES_BY_TAG: _evidence_ec2_instances_by_tag,
EvidenceSourceId.ELB_TARGET_HEALTH: _evidence_elb_target_health,
EvidenceSourceId.K8S_EVENTS: _evidence_k8s_events,
EvidenceSourceId.K8S_POD_METRICS: _evidence_k8s_pod_metrics,
EvidenceSourceId.K8S_NODE_METRICS: _evidence_k8s_node_metrics,
EvidenceSourceId.K8S_DNS_METRICS: _evidence_k8s_dns_metrics,
EvidenceSourceId.K8S_MESH_METRICS: _evidence_k8s_mesh_metrics,
EvidenceSourceId.K8S_ROLLOUT: _evidence_k8s_rollout,
}
def evaluate(
final_state: dict[str, Any],
required_source_ids: list[str],
) -> list[EvidencePresence]:
"""Evaluate which of *required_source_ids* are present in *final_state*.
Args:
final_state: The agent's completed investigation state dict.
required_source_ids: Semantic source ID strings from
``ScenarioAnswerKey.required_evidence_sources``.
Returns:
One ``EvidencePresence`` per required source, in input order.
"""
evidence = final_state.get("evidence") or {}
output_text = _build_output_text(final_state)
results: list[EvidencePresence] = []
for source_id_str in required_source_ids:
try:
source_id = EvidenceSourceId(source_id_str)
except ValueError:
results.append(
EvidencePresence(
source_id=source_id_str,
present=False,
reason=f"unknown source id {source_id_str!r}",
)
)
continue
if source_id == EvidenceSourceId.AWS_PERFORMANCE_INSIGHTS:
results.append(_evidence_performance_insights(evidence, output_text))
else:
predicate = _PREDICATES.get(source_id)
if predicate is None:
results.append(
EvidencePresence(
source_id=source_id_str,
present=False,
reason=f"no predicate registered for {source_id_str!r}",
)
)
else:
results.append(predicate(evidence))
return results
def missing_sources(
final_state: dict[str, Any],
required_source_ids: list[str],
) -> list[str]:
"""Return the subset of *required_source_ids* that are absent from *final_state*.
Returns plain ``str`` values (not enum instances) so they format cleanly in
f-strings and list reprs without ``<EvidenceSourceId...>`` noise.
"""
return [
presence.source_id.value
if isinstance(presence.source_id, EvidenceSourceId)
else str(presence.source_id)
for presence in evaluate(final_state, required_source_ids)
if not presence.present
]
def _build_output_text(final_state: dict[str, Any]) -> str:
"""Concatenate agent reasoning text for secondary PI signal detection."""
parts = [
str(final_state.get("root_cause") or ""),
" ".join(c.get("claim", "") for c in (final_state.get("validated_claims") or [])),
" ".join(c.get("claim", "") for c in (final_state.get("non_validated_claims") or [])),
" ".join(final_state.get("causal_chain") or []),
str(final_state.get("report") or ""),
str((final_state.get("problem_report") or {}).get("report_md") or ""),
]
return " ".join(parts)