Files
tracer-cloud--opensre/tests/synthetic/rds_postgres/README.md
T
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

145 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Synthetic RDS PostgreSQL Suite
This suite benchmarks RDS PostgreSQL root-cause analysis against bundled telemetry fixtures instead of live AWS infrastructure. Each scenario is a static evidence snapshot served through a `FixtureGrafanaBackend`, which drives the same agentic pipeline (`plan → investigate → diagnose`) used in production.
## Scenario table
### Axis 1 — Efficiency (marker: `synthetic`)
| ID | Name | Difficulty | True root cause | Adversarial element | Forbidden |
| --- | --------------------------------- | ---------- | ------------------- | ----------------------------------------------- | ----------------------------- |
| 000 | healthy | 1 | healthy | none | resource_exhaustion |
| 001 | replication-lag | 1 | replication_lag | none | — |
| 002 | connection-exhaustion | 1 | connection_exhaustion | none | — |
| 003 | storage-full | 1 | storage_exhaustion | none | — |
| 004 | cpu-saturation-bad-query | 1 | cpu_saturation | none | — |
| 005 | failover | 1 | multi_az_failover_health_check | none | — |
| 006 | replication-lag-cpu-redherring | 2 | replication_lag | CPUUtilization elevated (analytics job) | category: cpu_saturation |
| 007 | connection-pressure-noisy-healthy | 2 | healthy | CPU/connections oscillating near-threshold | category: connection_exhaustion |
| 008 | storage-full-missing-metric | 3 | storage_exhaustion | FreeStorageSpace absent from fixture | — |
| 009 | dual-fault-connection-cpu | 4 | connection_exhaustion | connections + CPU both failing, causally linked | keywords: storage, replication |
| 010 | replication-lag-missing-metric | 3 | replication_lag | ReplicaLag metric absent from fixture | — |
### Axis 2 — Reasoning (marker: `axis2`)
Axis 2 scenarios use `SelectiveGrafanaBackend`. The agent must ask for the right metrics and explicitly rule out alternative hypotheses. Each scenario has `ruling_out_keywords` that must appear in the agent's output.
| ID | Name | Difficulty | True root cause | Red herring / adversarial element | Must rule out |
| --- | ---------------------------------- | ---------- | ------------------- | -------------------------------------------------------------------- | ----------------------------------------- |
| 011 | cpu-storage-compositional | 4 | dual_resource_exhaustion | ReplicaLag elevation and connection spike as side effects | connection_exhaustion, replication |
| 012 | replication-lag-misleading-events | 3 | replication_lag | Three historical infra events in event stream (none are root cause) | infrastructure (failover as root cause) |
| 013 | storage-recovery-false-alert | 3 | healthy | FreeStorageSpace spike + WriteLatency brief elevation | resource_exhaustion (already recovered) |
| 014 | checkpoint-storm-cpu-saturation | 4 | checkpoint_io_storm | CPU at 92% — alert fires on CPU but cause is VACUUM checkpoint storm | cpu_saturation (CPU is symptom, not root) |
## Difficulty levels
| Level | Description |
| ----- | ----------- |
| 1 | Single dominant signal — all evidence consistent, root cause identifiable in one step |
| 2 | One confounder present — second evidence source needed to rule it out |
| 3 | Absent or indirect evidence — key metric missing, or misleading signals require timeline reasoning |
| 4 | Compositional fault — two failure modes active; agent must identify both and correctly characterise causally-linked side effects |
## MECE basis
Uniqueness is on `(primary_signal × rate × corroborating_presence × event_presence)`, not on primary signal alone.
003 and 008 both map to `storage_full` but have distinct fingerprints:
- **003**: `FreeStorageSpace` present and trending to 0 with elevated `WriteIOPS`
- **008**: `FreeStorageSpace` absent from the fixture entirely — agent must infer from events + PI write latency
## Scoring
### Axis 1 (all scenarios — `test_suite.py`)
Each scenario passes when all of the following are true:
1. The model returns a non-empty root cause
2. The predicted `ROOT_CAUSE_CATEGORY` matches `answer.yml`
3. Every required keyword from `answer.yml:required_keywords` appears in the output
4. The actual category is not in `answer.yml:forbidden_categories` (level 2+ scenarios)
5. No forbidden keyword from `answer.yml:forbidden_keywords` appears in the output (level 4 scenario)
6. Every source listed in `answer.yml:required_evidence_sources` is non-empty in `final_state["evidence"]` — proves the agent consulted the right evidence, not just keyword-matched the alert title
Additionally, a `TrajectoryScore` is computed for each scenario with an `optimal_trajectory`:
- `sequencing_ok`: all expected action types appear in the agent's executed action log (set membership; parallel execution order is non-deterministic)
- `calibration_ok`: number of investigation loops ≤ `max_investigation_loops`
- `efficiency_score`: mean(sequencing_ok, calibration_ok); 1.0 = full pass
### Axis 2 (adversarial scenarios — `test_suite_axis2.py`, marker: `axis2`)
Axis 2 runs through `SelectiveGrafanaBackend`, which:
- Returns only the metric series matching the agent's `metric_name` query (case-insensitive substring)
- Records every metric name the agent requested in `queried_metrics` (audit log)
On top of all Axis 1 checks, Axis 2 asserts a `ReasoningScore`:
- `ruling_out_ok`: every token in `answer.yml:ruling_out_keywords` appears in agent output (proves the agent addressed and dismissed alternative hypotheses)
- `queries_ok`: every entry in `answer.yml:required_queries` was requested by the agent via `query_timeseries`**not yet testable**: the current action registry hardcodes `metric_name="pipeline_runs_total"` for all `query_grafana_metrics` calls; `required_queries` is reserved for when the agent supports per-metric querying
- `reasoning_score`: mean(ruling_out_ok, queries_ok); 1.0 = full pass
### Gap metric
The gap between Axis 1 and Axis 2 pass rates is the primary health indicator for adversarial robustness. A large gap means the agent can find answers when handed all data but cannot reason when it must choose what to look at. Track it per difficulty level:
```bash
python -m tests.synthetic.rds_postgres.run_suite --mock-grafana --axis2
```
## Each scenario folder contains
- `scenario.yml`: scenario metadata (engine, difficulty, adversarial_signals, depends_on)
- `alert.json`: synthetic alert payload
- `aws_cloudwatch_metrics.json`: CloudWatch metric evidence (may omit metrics to simulate collection gaps)
- `aws_rds_events.json`: RDS event stream for the incident window
- `aws_performance_insights.json`: top SQL and wait-event evidence
- `answer.yml`: expected category, required keywords, optional forbidden constraints, required evidence sources
## Running
Via the interactive CLI (recommended):
```bash
opensre tests synthetic
```
Run the whole Axis 1 suite directly:
```bash
python -m tests.synthetic.rds_postgres.run_suite --mock-grafana
```
Run Axis 2 adversarial scenarios via pytest:
```bash
pytest -m axis2 tests/synthetic/rds_postgres/test_suite_axis2.py -v
```
Run a single scenario:
```bash
python -m tests.synthetic.rds_postgres.run_suite --scenario 006-replication-lag-cpu-redherring --mock-grafana
```
Print JSON results:
```bash
python -m tests.synthetic.rds_postgres.run_suite --mock-grafana --json
```
## CI tier strategy
- **Axis 1, Levels 12** (scenarios 000007): run on every commit (`@synthetic`)
- **Axis 1, Levels 34** (scenarios 008010): deferred to nightly — require indirect inference
- **Axis 2** (scenarios 011013, `@axis2`): run nightly alongside Axis 1 levels 34; gap is reported each run
## Known gaps
- **Temporal ordering**: all scenarios deliver evidence as a static snapshot. Production delivers evidence incrementally (alert fires → query metrics → query events → …). Testing temporal ordering requires architectural changes to the fixture backend and is out of scope.
- **Level 4 coverage**: two compositional fault scenarios (009, 011). A fuller curriculum would include 34 dual-fault combinations across different failure mode pairs.
- **Slack/markdown renderer for multi-fault**: the renderer displays a single `root_cause` string. Compositional faults may eventually need a `root_causes: list` field in the schema.
- **Axis 2 `required_queries` not yet enforced**: The agent action registry hardcodes `metric_name="pipeline_runs_total"` for all `query_grafana_metrics` calls. `SelectiveGrafanaBackend` records all queried metric names as an audit log but does not filter results. When the agent is updated to pass dynamic CloudWatch metric names (e.g. `metric_name="CPUUtilization"`), re-enable filtering in `SelectiveGrafanaBackend.query_timeseries` and set `required_queries` in `answer.yml`.
## Dependency: healthy_rca_state
Scenario 007 depends on `HEALTHY_SHORT_CIRCUIT=true` (the default) and the `healthy` category being wired into the LLM prompt. If you run with `HEALTHY_SHORT_CIRCUIT=false`, scenario 007 will fall through to the LLM path, which should still classify as `healthy` — but the test is most deterministic with the short-circuit enabled.