{"id":47826510,"url":"https://github.com/usetero/policy-conformance","last_synced_at":"2026-04-03T19:44:50.363Z","repository":{"id":338059185,"uuid":"1156414361","full_name":"usetero/policy-conformance","owner":"usetero","description":"Conformance test suite for validating Policy specification implementations.","archived":false,"fork":false,"pushed_at":"2026-04-01T21:00:42.000Z","size":9542,"stargazers_count":0,"open_issues_count":8,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-04-02T08:44:09.907Z","etag":null,"topics":["conformance","observability","policy","telemetry","testing"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/usetero.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-02-12T16:13:16.000Z","updated_at":"2026-03-04T21:53:38.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/usetero/policy-conformance","commit_stats":null,"previous_names":["usetero/policy-conformance"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/usetero/policy-conformance","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/usetero%2Fpolicy-conformance","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/usetero%2Fpolicy-conformance/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/usetero%2Fpolicy-conformance/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/usetero%2Fpolicy-conformance/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/usetero","download_url":"https://codeload.github.com/usetero/policy-conformance/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/usetero%2Fpolicy-conformance/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31374021,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-03T17:53:18.093Z","status":"ssl_error","status_checked_at":"2026-04-03T17:53:17.617Z","response_time":107,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["conformance","observability","policy","telemetry","testing"],"created_at":"2026-04-03T19:44:47.401Z","updated_at":"2026-04-03T19:44:50.340Z","avatar_url":"https://github.com/usetero.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# policy-conformance\n\nConformance test suite for\n[Policy spec](https://github.com/usetero/policy/blob/master/spec.md)\nimplementations. Verifies that policy evaluation engines in Go, Rust, and Zig\nproduce identical results when given the same policies and OpenTelemetry input\ndata.\n\n## Repository structure\n\n```\n.\n├── Taskfile.yml              # Test harness (build, test, bench, clean)\n├── runners/\n│   ├── go/                   # Go conformance runner (policy-go)\n│   ├── rs/                   # Rust conformance runner (policy-rs)\n│   └── zig/                  # Zig conformance runner (policy-zig)\n├── server/                   # HTTP/gRPC conformance server (Go)\n├── testcases/                # 184 test case directories\n│   ├── logs_*/               # Log signal tests\n│   ├── metrics_*/            # Metric signal tests\n│   ├── traces_*/             # Trace signal tests\n│   └── compound_*/           # Multi-signal / multi-batch tests\n└── bin/                      # Hermit-managed toolchain\n```\n\n### Test case layout\n\nEach test case is a directory under `testcases/` containing:\n\n**Simple test** (single input/output):\n\n```\ntestcases/logs_severity_drop/\n├── policies.json             # Policy definitions\n├── input.json                # OTLP JSON input\n├── expected.json             # Expected OTLP JSON output\n└── expected_stats.json       # Expected match statistics\n```\n\nThe harness runs a simple test as follows:\n\n1. Detect signal type from the directory name prefix (`logs_*` → log,\n   `metrics_*` → metric, `traces_*` → trace)\n2. Invoke the runner:\n   ```\n   ./runner-go --policies policies.json --input input.json \\\n               --output output_go.json --stats stats_go.json --signal log\n   ```\n3. Normalize both `expected.json` and `output_go.json` with jq (strip null\n   fields, coerce numeric strings to numbers, sort keys)\n4. Diff the normalized output against `expected.json` — any difference is a\n   failure\n5. Diff `stats_go.json` against `expected_stats.json` — any difference is a\n   failure\n6. Report PASS or FAIL (on failure, print the diff)\n\n**Compound test** (multiple batches, stats checked once after all batches):\n\n```\ntestcases/compound_mixed_signals/\n├── policies.json             # Policy definitions (may span signals)\n├── input_1.json              # Batch 1 (e.g., logs)\n├── expected_1.json           # Expected output for batch 1\n├── input_2.json              # Batch 2 (e.g., metrics)\n├── expected_2.json           # Expected output for batch 2\n├── input_3.json              # Batch 3 (e.g., traces)\n├── expected_3.json           # Expected output for batch 3\n└── expected_stats.json       # Merged stats across all batches\n```\n\nThe harness runs a compound test as follows:\n\n1. Iterate over `input_N.json` files sorted numerically\n2. For each batch N:\n   1. Detect signal type from the JSON content (`resourceLogs` → log,\n      `resourceMetrics` → metric, `resourceSpans` → trace)\n   2. Invoke the runner with `input_N.json`, writing `output_N_go.json` and\n      `stats_N_go.json`\n   3. Normalize and diff `output_N_go.json` against `expected_N.json`\n3. After all batches, merge per-batch stats files with jq (sum `hits` and\n   `misses` per `policy_id`)\n4. Diff the merged stats against `expected_stats.json`\n5. Report PASS or FAIL (on failure, print diffs for each failing batch and/or\n   stats)\n\n### Runners\n\nAll three runners implement the same CLI interface:\n\n```\nrunner-{go,rs,zig} \\\n  --policies policies.json \\\n  --input input.json \\\n  --output output.json \\\n  --stats stats.json \\\n  --signal {log,metric,trace}\n```\n\nFor HTTP/gRPC mode, `--policies` is replaced with `--server URL` or\n`--grpc ADDR`.\n\n| Runner       | Language | Policy engine | Protobuf codec              |\n| ------------ | -------- | ------------- | --------------------------- |\n| `runner-go`  | Go       | `policy-go`   | `protojson`                 |\n| `runner-rs`  | Rust     | `policy-rs`   | `serde` + custom OTel types |\n| `runner-zig` | Zig      | `policy-zig`  | Native proto JSON codec     |\n\n## Prerequisites\n\n- [Task](https://taskfile.dev/) (provided via `bin/`)\n- Go 1.26+\n- Rust (stable)\n- Zig 0.15+\n- [Hyperscan/Vectorscan](https://www.hyperscan.io/) (`task ci:setup` installs\n  it)\n- `jq` (provided via `bin/`)\n\n## Running tests\n\n### Build everything\n\n```sh\ntask build       # Build all runners + conformance server\n```\n\n### File-based provider (CLI mode)\n\nRuns each runner as a CLI process that reads policies from a local JSON file:\n\n```sh\ntask test        # Run all 3 runners\ntask test:go     # Go only\ntask test:rs     # Rust only\ntask test:zig    # Zig only\n```\n\n### HTTP provider (server mode)\n\nRuns the conformance server per test case, then uses the runner's `--server`\nflag to fetch policies over HTTP:\n\n```sh\ntask test:http       # All 3 runners via HTTP\ntask test:http:go    # Go only\ntask test:http:rs    # Rust only\ntask test:http:zig   # Zig only\n```\n\n**What happens for each http test case:**\n\n1. Starts the conformance server on a random port:\n   ```\n   ./conformance-server --policies testcases/X/policies.json --http-port 0 --grpc-port 0\n   ```\n2. Reads `HTTP_PORT=N` and `GRPC_PORT=N` from stdout (via FIFO, no sleeps)\n3. Invokes the runner:\n   ```\n   ./runner-go --server http://localhost:PORT/v1/policy/sync \\\n               --input testcases/X/input.json \\\n               --output testcases/X/output_go_http.json \\\n               --signal log\n   ```\n4. Fetches accumulated stats from `GET /stats`\n5. Shuts down the server via `GET /shutdown`\n6. Diffs output and stats (stats normalization strips `misses` and zero-hit\n   policies since the server only reports `{policy_id, hits}` for matched\n   policies)\n\n### gRPC provider\n\nSame as HTTP but uses `--grpc` flag:\n\n```sh\ntask test:grpc       # Go + Rust via gRPC\ntask test:grpc:go\ntask test:grpc:rs\n```\n\n\u003e Note: The Zig runner does not support gRPC.\n\n### Other commands\n\n```sh\ntask test:repeat TC=traces_sampling_50pct N=100 R=go   # Repeat one test N times\ntask bench                                              # Benchmark all runners with hyperfine\ntask clean                                              # Remove build artifacts and outputs\n```\n\n## Known issues\n\n- `traces_event_attribute` and `traces_link_trace_id` are unimplemented across\n  all runners\n\n## Test case catalog\n\nAll 184 test cases listed below pass for all three runners (Go, Rust, Zig) in\nboth file-based and HTTP modes unless noted otherwise.\n\n### Logs — matching\n\n| Test case                                 | Description                                                    | Go                 | Zig                | Rust               |\n| ----------------------------------------- | -------------------------------------------------------------- | ------------------ | ------------------ | ------------------ |\n| `logs_all_dropped`                        | All log records match a drop policy; output is empty           | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_attribute_match`                    | Match log records by log attribute exact value                 | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_case_insensitive_ends_with`         | Case-insensitive `ends_with` matcher on severity               | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_case_insensitive_exact`             | Case-insensitive `exact` matcher on body                       | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_case_insensitive_regex`             | Case-insensitive regex matcher on body                         | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_case_insensitive_starts_with`       | Case-insensitive `starts_with` matcher on severity             | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_contains_ci`                        | Case-insensitive `contains` matcher on body                    | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_contains_cs`                        | Case-sensitive `contains` matcher on body                      | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_empty_input`                        | Empty input (no log records) produces empty output             | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_empty_vs_missing_field`             | Distinguish between empty string and missing/null field        | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_enabled_false`                      | Disabled policy (`enabled: false`) is skipped entirely         | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_enabled_false_with_transforms`      | Disabled policy with transforms; transforms must not fire      | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_ends_with`                          | `ends_with` matcher on severity text                           | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_event_name_field`                   | Match on the `event_name` log field                            | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_exact_drop`                         | Exact match on severity drops matching records                 | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_exists`                             | `exists: true` matcher on log attribute                        | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_exists_false`                       | `exists: false` matcher — match when attribute is absent       | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_keep_all_default`                   | Policy with `keep: \"all\"` passes all matched records through   | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_multiple_matchers`                  | Policy with multiple matchers (AND logic)                      | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_multiple_policies_most_restrictive` | Most-restrictive keep wins when multiple policies match        | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_multiple_resources`                 | Multiple resources in input processed independently            | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_negated_match`                      | `negate: true` inverts a matcher                               | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_nested_attribute`                   | Match on nested attribute path (e.g., `[\"http\", \"method\"]`)    | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_nested_attribute_deep`              | Match on deeply nested attribute path (3+ levels)              | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_no_match`                           | No policy matches; all records pass through unmodified         | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_overlapping_policies`               | Multiple policies match the same record                        | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_policy_ordering_determinism`        | Policies evaluated in deterministic (alphanumeric by ID) order | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_regex_drop`                         | Regex matcher drops matching records                           | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_resource_attr`                      | Match on resource attribute                                    | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_resource_schema_url`                | Match on resource schema URL                                   | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_scope_attr`                         | Match on scope attribute                                       | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_scope_schema_url`                   | Match on scope schema URL                                      | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_severity_drop`                      | Drop by severity text exact match                              | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_span_id_field`                      | Match on the `span_id` log field                               | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_starts_with`                        | `starts_with` matcher on severity text                         | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_three_matchers`                     | Three matchers combined in a single policy (AND)               | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_trace_id_field`                     | Match on the `trace_id` log field                              | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n\n### Logs — sampling and rate limiting\n\n| Test case                       | Description                                            | Go                 | Zig                | Rust               |\n| ------------------------------- | ------------------------------------------------------ | ------------------ | ------------------ | ------------------ |\n| `logs_rate_limit`               | Rate limit to N records per second                     | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_rate_limit_drop_overlap`  | `keep: \"none\"` overrides rate limit on the same record | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_rate_limit_per_minute`    | Rate limit specified as N per minute                   | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_sample_key_attribute`     | Sampling keyed by log attribute value                  | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_sample_key_resource_attr` | Sampling keyed by resource attribute value             | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_sample_key_scope_attr`    | Sampling keyed by scope attribute value                | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_sampling_10pct`           | 10% sampling rate                                      | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_sampling_25pct`           | 25% sampling rate                                      | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_sampling_50pct`           | 50% sampling rate                                      | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_sampling_75pct`           | 75% sampling rate                                      | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_sampling_drop_overlap`    | `keep: \"none\"` overrides sampling on the same record   | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n\n### Logs — transforms\n\n| Test case                                    | Description                                                      | Go                 | Zig                | Rust               |\n| -------------------------------------------- | ---------------------------------------------------------------- | ------------------ | ------------------ | ------------------ |\n| `logs_transform_add_attr_upsert_absent`      | Add attribute with `upsert: true` when field absent (insert)     | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_transform_add_attribute`               | Add a new log attribute                                          | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_transform_add_body`                    | Add body to log record when body is null                         | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_transform_add_body_no_upsert_exists`   | Add body without upsert when body exists (no-op)                 | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_transform_add_body_upsert_exists`      | Add body with `upsert: true` when body exists (overwrite)        | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_transform_add_no_upsert`               | Add attribute with `upsert: false` when field exists (no-op)     | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_transform_add_no_upsert_new_field`     | Add attribute with `upsert: false` when field absent (insert)    | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_transform_add_resource_attr`           | Add a new resource attribute                                     | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_transform_add_scope_attr`              | Add a new scope attribute                                        | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_transform_add_upsert`                  | Add attribute with `upsert: true` overwrites existing value      | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_transform_drop_skips_transform`        | Transforms are not applied to records dropped by `keep: \"none\"`  | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_transform_execution_order`             | Transforms execute in spec order: remove → redact → rename → add | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_transform_multiple_policies`           | Multiple policies each apply their own transforms                | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_transform_multiple_same_field`         | Multiple transforms targeting the same field in one policy       | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_transform_redact_attribute`            | Redact a log attribute value with `[REDACTED]`                   | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_transform_redact_body`                 | Redact the log body field                                        | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_transform_redact_nonexistent`          | Redact a non-existent field (no-op)                              | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_transform_redact_resource_attr`        | Redact a resource attribute                                      | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_transform_redact_scope_attr`           | Redact a scope attribute                                         | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_transform_remove_attribute`            | Remove a log attribute                                           | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_transform_remove_body`                 | Remove the log body field                                        | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_transform_remove_nonexistent`          | Remove a non-existent field (no-op)                              | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_transform_remove_resource_attr`        | Remove a resource attribute                                      | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_transform_remove_scope_attr`           | Remove a scope attribute                                         | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_transform_rename_attribute`            | Rename a log attribute                                           | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_transform_rename_no_upsert`            | Rename with `upsert: false` when target exists (no-op)           | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_transform_rename_nonexistent`          | Rename a non-existent source attribute (no-op)                   | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_transform_rename_resource_attr`        | Rename a resource attribute                                      | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_transform_rename_scope_attr`           | Rename a scope attribute                                         | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_transform_rename_source_absent`        | Rename when source attribute absent, `upsert: false` (no-op)     | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_transform_rename_target_absent`        | Rename when target absent, `upsert: false` (normal rename)       | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_transform_rename_upsert`               | Rename with `upsert: true` overwrites existing target            | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_transform_rename_upsert_source_absent` | Rename with `upsert: true` when source absent (no-op)            | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_transform_rename_upsert_target_absent` | Rename with `upsert: true` when target absent (rename)           | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_transform_with_rate_limit`             | Transforms applied to records that survive rate limiting         | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `logs_transform_with_sampling`               | Transforms applied to records that survive sampling              | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n\n### Metrics\n\n| Test case                            | Description                                         | Go                 | Zig                | Rust               |\n| ------------------------------------ | --------------------------------------------------- | ------------------ | ------------------ | ------------------ |\n| `metrics_aggregation_temporality`    | Match by aggregation temporality (delta/cumulative) | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `metrics_case_insensitive`           | Case-insensitive metric name matching               | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `metrics_cumulative_temporality`     | Match cumulative temporality specifically           | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `metrics_description`                | Match by metric description field                   | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `metrics_drop_by_attr`               | Drop metrics by datapoint attribute                 | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `metrics_drop_by_name`               | Drop metrics by name exact match                    | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `metrics_empty_input`                | Empty input (no metrics) produces empty output      | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `metrics_ends_with`                  | `ends_with` matcher on metric name                  | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `metrics_exists`                     | `exists: true` matcher on datapoint attribute       | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `metrics_exists_false`               | `exists: false` matcher on datapoint attribute      | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `metrics_exponential_histogram_type` | Match exponential histogram metric type             | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `metrics_histogram_type`             | Match histogram metric type                         | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `metrics_keep`                       | Basic keep policy for metrics                       | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `metrics_multiple_matchers`          | Multiple matchers combined (AND logic) for metrics  | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `metrics_multiple_policies`          | Multiple metric policies evaluated together         | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `metrics_multiple_resources`         | Multiple resources in metric input                  | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `metrics_negate`                     | Negated matcher for metrics                         | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `metrics_negate_temporality`         | Negated temporality matcher                         | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `metrics_negate_type`                | Negated metric type matcher                         | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `metrics_overlapping_miss`           | Overlapping policies where one misses               | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `metrics_resource_attr`              | Match on resource attribute for metrics             | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `metrics_resource_schema_url`        | Match on resource schema URL for metrics            | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `metrics_scope_attr`                 | Match on scope attribute for metrics                | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `metrics_scope_name`                 | Match on scope name for metrics                     | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `metrics_scope_schema_url`           | Match on scope schema URL for metrics               | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `metrics_scope_version`              | Match on scope version for metrics                  | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `metrics_starts_with`                | `starts_with` matcher on metric name                | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `metrics_sum_type`                   | Match sum metric type                               | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `metrics_summary_type`               | Match summary metric type                           | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `metrics_three_policies`             | Three metric policies evaluated together            | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `metrics_type_filter`                | Filter metrics by type (gauge/sum/histogram)        | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `metrics_unit`                       | Match by metric unit field                          | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n\n### Traces — matching\n\n| Test case                        | Description                                     | Go                 | Zig                | Rust               |\n| -------------------------------- | ----------------------------------------------- | ------------------ | ------------------ | ------------------ |\n| `traces_case_insensitive`        | Case-insensitive span name matching             | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `traces_drop_0pct`               | Drop at 0% (all sampled out)                    | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `traces_empty_input`             | Empty input (no spans) produces empty output    | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `traces_error_vs_health`         | Distinguish error spans from health check spans | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `traces_event_name`              | Match on span event name                        | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `traces_exists`                  | `exists: true` matcher on span attribute        | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `traces_exists_false`            | `exists: false` matcher on span attribute       | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `traces_multiple_matchers`       | Multiple matchers combined (AND) for traces     | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `traces_multiple_resources`      | Multiple resources in trace input               | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `traces_name_contains`           | `contains` matcher on span name                 | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `traces_name_ends_with`          | `ends_with` matcher on span name                | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `traces_name_regex`              | Regex matcher on span name                      | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `traces_name_starts_with`        | `starts_with` matcher on span name              | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `traces_negate`                  | Negated matcher for traces                      | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `traces_negate_span_kind`        | Negated span kind matcher                       | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `traces_negate_span_status`      | Negated span status matcher                     | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `traces_overlapping`             | Overlapping trace policies on the same spans    | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `traces_parent_span_id`          | Match on parent span ID field                   | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `traces_resource_attr`           | Match on resource attribute for traces          | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `traces_scope_attr`              | Match on scope attribute for traces             | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `traces_scope_name`              | Match on scope name for traces                  | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `traces_scope_schema_url`        | Match on scope schema URL for traces            | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `traces_scope_version`           | Match on scope version for traces               | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `traces_span_attribute`          | Match on span attribute exact value             | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `traces_span_attribute_contains` | `contains` matcher on span attribute            | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `traces_span_kind`               | Match on span kind (server)                     | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `traces_span_kind_client`        | Match on span kind (client)                     | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `traces_span_kind_consumer`      | Match on span kind (consumer)                   | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `traces_span_kind_producer`      | Match on span kind (producer)                   | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `traces_span_status_error`       | Match on span status = error                    | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `traces_span_status_ok`          | Match on span status = ok                       | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `traces_span_status_unset`       | Match on span status = unset                    | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `traces_trace_state`             | Match on trace state field                      | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n\n### Traces — sampling\n\n| Test case                      | Description                                             | Go                 | Zig                | Rust               |\n| ------------------------------ | ------------------------------------------------------- | ------------------ | ------------------ | ------------------ |\n| `traces_keep_100pct`           | Keep at 100% (all sampled in, writes `th:0` tracestate) | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `traces_sampling_10pct`        | 10% trace sampling with deterministic hash              | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `traces_sampling_25pct`        | 25% trace sampling                                      | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `traces_sampling_50pct`        | 50% trace sampling                                      | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `traces_sampling_75pct`        | 75% trace sampling                                      | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `traces_sampling_equalizing`   | Equalizing sampling algorithm                           | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `traces_sampling_fail_closed`  | `fail_closed: true` drops spans without valid trace ID  | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `traces_sampling_precision`    | High-precision sampling threshold encoding              | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `traces_sampling_proportional` | Proportional sampling algorithm                         | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n\n### Traces — tracestate\n\n| Test case                                    | Description                                               | Go                 | Zig                | Rust               |\n| -------------------------------------------- | --------------------------------------------------------- | ------------------ | ------------------ | ------------------ |\n| `traces_tracestate_equalizing_incoming_th`   | Equalizing sampler with pre-existing `th` in tracestate   | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `traces_tracestate_fail_closed_true`         | Fail-closed behavior with tracestate present              | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `traces_tracestate_mixed`                    | Mixed tracestate scenarios (some with, some without)      | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `traces_tracestate_overwrite_ot`             | Overwrite existing `ot` vendor key in tracestate          | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `traces_tracestate_preserve_vendors`         | Preserve non-`ot` vendor keys in tracestate               | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `traces_tracestate_proportional_incoming_th` | Proportional sampler with pre-existing `th` in tracestate | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `traces_tracestate_rv_consistency_check`     | Randomness value consistency check in tracestate          | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `traces_tracestate_rv_randomness`            | Random value (`rv`) written to tracestate                 | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `traces_tracestate_write_basic`              | Basic tracestate write with sampling threshold            | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n\n### Compound tests\n\n| Test case                                  | Description                                                                      | Go                 | Zig                | Rust               |\n| ------------------------------------------ | -------------------------------------------------------------------------------- | ------------------ | ------------------ | ------------------ |\n| `compound_all_keep_types`                  | All keep types (all/none/sample/rate_limit) in one policy set                    | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `compound_conflicting_keeps`               | Conflicting keep decisions across policies; most restrictive wins                | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `compound_datapoint_attr_types`            | Datapoint attribute matching across histogram, summary, gauge                    | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `compound_disabled_mixed`                  | Mix of enabled and disabled policies; disabled transforms must not fire          | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `compound_double_negation`                 | `exists: false` + `negate: true` semantics                                       | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `compound_empty_vs_missing`                | Empty string vs null/absent field behavior across signals                        | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `compound_many_policies_fanout`            | 50+ policies each targeting a different service; verifies no cross-contamination | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `compound_mixed_signals`                   | Policies spanning logs, metrics, and traces in one set                           | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `compound_negation_overlap`                | Policies with negated matchers creating complex intersections                    | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `compound_nested_attributes`               | Nested attribute paths across all signal types                                   | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `compound_rate_limit_most_restrictive`     | `keep: \"none\"` overrides rate limit; confirms none \u003e rate_limit                  | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `compound_regex_edge_cases`                | Character classes, anchoring, alternation, UUID patterns, escaped brackets       | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `compound_sampling_interactions`           | Trace sampling with fail_closed, 0% drop overriding sampling                     | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `compound_scope_isolation`                 | Resource/scope attribute transforms are isolated per scope                       | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `compound_transform_chain`                 | Cross-policy transform visibility (transforms applied after all matching)        | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `compound_transform_ordering_alphanumeric` | Policies evaluated in alphanumeric ID order, not array order                     | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| `compound_transforms_across_policies`      | Multiple policies with add/redact/rename transforms on same records              | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n\n### Summary\n\n| Signal    | Tests   | Go      | Zig     | Rust    |\n| --------- | ------- | ------- | ------- | ------- |\n| Logs      | 84      | 84      | 84      | 84      |\n| Metrics   | 32      | 32      | 32      | 32      |\n| Traces    | 51      | 51      | 51      | 51      |\n| Compound  | 17      | 16      | 17      | 16      |\n| **Total** | **184** | **183** | **184** | **183** |\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fusetero%2Fpolicy-conformance","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fusetero%2Fpolicy-conformance","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fusetero%2Fpolicy-conformance/lists"}