Skip to content

v0.5.17

Choose a tag to compare

@github-actions github-actions released this 02 May 15:09
· 580 commits to main since this release

What's new in v0.5.17

v0.5.17 introduces team-wide acknowledgments for findings. Two architects asked for a way to silence findings the team has accepted as known and intentional, so the next CI run focuses on what is new instead of re-reporting the same baseline. The decisions live in a TOML file at the root of the application repo, every change goes through normal PR review, and git log .perf-sentinel-acknowledgments.toml is the audit trail. This is the CI / batch path of a two-part feature: the daemon-side runtime ack (sticky entries with optional TTL stored in a local SQLite) is deferred to a later release pending architecture review.

The release also expands the published Grafana dashboard from 8 to 17 panels and lifts coverage of registered daemon metrics to 11/11 (was 6/11). The new panels surface the OTLP HTTP retry-after gate, sampling drops, the daemon batcher histograms, the actionable-fix coverage ratio (a CI-batch signal that drives the IDE perf-lint plugin), and the cold-start signal exposed by the Report.warnings field shipped in 0.5.16.

Added

  • .perf-sentinel-acknowledgments.toml file at the repo root. TOML format, one [[acknowledged]] block per ack. Required fields: signature, acknowledged_by, acknowledged_at, reason. Optional: expires_at = "YYYY-MM-DD" for a periodic re-evaluation requirement. A typo in any required field or a malformed expires_at fails the run loud rather than silently widening the matched set. The loader caps file size at 16 MiB so a stray --acknowledgments /dev/zero cannot exhaust process memory.
  • Finding.signature: String field, always emitted in JSON output. Format <finding_type>:<service>:<sanitized_endpoint>:<sha256-prefix-of-template> (16-hex prefix, ~64 bits of collision resistance). The triple already discriminates by service and endpoint, so the hash only disambiguates templates within the same triple, which is an extremely small population in practice. Operators copy-paste the value directly from analyze --format json | jq '.findings[].signature' into the ack file. Additive on pre-0.5.17 baselines via #[serde(default)].
  • Report.acknowledged_findings: Vec<AcknowledgedFinding> field, populated when the ack file matches at least one finding. Hidden from the wire payload by default, surfaced via --show-acknowledged. Each entry pairs the original Finding with the matching Acknowledgment metadata. Additive via serde(default, skip_serializing_if = "Vec::is_empty").
  • Three CLI flags on analyze, report, inspect, diff, tempo, jaeger-query: --acknowledgments <path> (override the default ./.perf-sentinel-acknowledgments.toml), --no-acknowledgments (disable filtering, audit view), --show-acknowledged (include ack details in output). inspect omits --show-acknowledged because the TUI does not yet have a dedicated panel, the status footer surfaces the count.
  • SARIF properties extended with acknowledged: true, acknowledgmentReason, acknowledgmentBy, acknowledgmentAt on results emitted from acknowledged findings (only when --show-acknowledged). Existing SARIF consumers parse without change because the new properties are additive. Free-text values are stripped of Unicode BiDi-override and invisible-format characters before emission, matching the sanitize_sarif_filepath discipline so a hostile acknowledged_by cannot spoof the displayed identity in GitHub or GitLab UIs.
  • Quality gate re-evaluation after ack filtering, so an N+1 SQL critical finding that was the only blocker for n_plus_one_sql_critical_max = 0 flips the gate from FAIL to PASS once acked. The io_waste_ratio_max rule is unaffected because it reads from raw spans (not findings), this asymmetry is documented in docs/ACKNOWLEDGMENTS.md. Acks are applied to both sides of diff so a finding suppressed on both sides drops out of the diff entirely.
  • 17-panel Grafana dashboard at examples/grafana-dashboard.json (was 8 panels). Coverage of registered daemon metrics is now 11/11. New panels: OTLP HTTP retry-after gate, sampling drops, batch processing histograms, actionable-fix coverage ratio, cold-start Report.warnings signal, and three additional rate / latency views aligned with the simulation-lab verify-grafana-dashboard scenario. Single source of truth: the lab's previously distinct French overview at manifests/grafana-dashboards/perf-sentinel-overview.json is replaced by a verbatim copy of this file, with a CI parity check.
  • 17 unit tests in crates/sentinel-core/src/acknowledgments.rs covering signature determinism + format, expired vs future vs permanent acks, gate re-evaluation, file load with valid / missing-field / malformed-date inputs, the 16 MiB size cap, the no-op when the file is absent, and the round-trip safety guarantee that a Report fed back through apply_to_report cannot accumulate stale ack pairs across runs.
  • 6 e2e CLI tests in crates/sentinel-cli/tests/e2e.rs covering the four-flag matrix (default, --acknowledgments, --no-acknowledgments, --show-acknowledged), signature emission in JSON output, and the no-op when the ack file is absent in the cwd.
  • New documentation: docs/ACKNOWLEDGMENTS.md (EN) and docs/FR/ACKNOWLEDGMENTS-FR.md (FR) with the full workflow, signature format, FAQ. Cross-references from README.md / README-FR.md, docs/CONFIGURATION.md / FR mirror, and a new "Investigating an unexpected ack" section in docs/RUNBOOK.md / FR mirror.

Changed

  • pipeline::analyze populates Finding.signature at the end of detection via the shared acknowledgments::enrich_with_signatures(&mut findings) helper. The daemon ingestion loop (daemon/event_loop.rs) does the same so live snapshots from /api/export/report carry signatures usable for ack matching. CLI Report-from-baseline paths (cmd_report --input <baseline.json>, cmd_diff --before, cmd_inspect --input <baseline.json>) call enrich_with_signatures after deserialization so pre-0.5.17 baselines (without the signature field) still match acks correctly.
  • emit_report_and_gate signature now takes &mut Report so the JSON / SARIF emit paths hide acknowledged_findings via a zero-copy mem::take + restore around the emit call. Avoids the deep-clone of the entire Report just to clear one field. The text sink always sees the live report so the count footer can surface acked entries even when their full detail is suppressed.

Behavior

  • Default behavior preserved when no ack file exists. A run in a directory without .perf-sentinel-acknowledgments.toml produces identical output to 0.5.16, no error message, no warning. The new Finding.signature field is additive and does not alter existing JSON consumers because they ignore unknown fields.
  • HTML dashboard payload embeds acknowledged_findings only when --show-acknowledged is set on report. The JS template does not yet visually distinguish ack rows, downstream tooling can grep the embedded JSON for ack metadata. A dedicated UI panel is on the dashboard roadmap.
  • GreenOps semantics intentional. Acknowledged findings are excluded from the quality gate (the entire point of "won't fix / accepted" semantics) but the carbon and waste numbers (io_waste_ratio, per-endpoint IIS, CO2 estimates) stay unchanged. An ack is a triage decision, not a physical mitigation: the I/O work is still happening, the energy is still being burned. The dashboard reflects honest accounting, the CI alert routing is what the ack controls.

Documentation

  • README.md and README-FR.md gain an "Acknowledging known findings" / "Acquitter les findings connus" section between the score-interpretation block and the architecture diagram. Both READMEs now also reference the perf-sentinel-simulation-lab companion repo, which validates eight operational modes end-to-end on a real Kubernetes cluster (hybrid daemon-to-batch HTML, batch over Tempo, daemon OTLP direct, multi-format Jaeger / Zipkin, calibrate, sidecar, cross-trace correlation, pg_stat_statements integration). Each scenario ships a Mermaid architecture diagram, the exact inputs and outputs, the required configuration, and the gotchas that surfaced during validation.
  • docs/CONFIGURATION.md and docs/FR/CONFIGURATION-FR.md document the file format, loading rules, and the no-glob-no-wildcard decision.
  • docs/RUNBOOK.md and docs/FR/RUNBOOK-FR.md add an "Investigating an unexpected ack" section with the three-step diagnostic recipe (--no-acknowledgments to compare, --show-acknowledged to surface metadata, git log for the audit trail).
  • docs/ACKNOWLEDGMENTS.md and docs/FR/ACKNOWLEDGMENTS-FR.md are new dedicated docs covering the full workflow, signature anatomy, quality gate semantics, and FAQ (handling stale acks, no-glob-by-design, inspect and HTML limitations).

Dependencies

  • sha2 = "0.11.0" added as a direct dependency of sentinel-core for the canonical signature hash. The 0.11 line moved from generic-array to hybrid-array, so it does not unify with the sha2 0.10.x still pulled transitively by rustls and both versions ship in the binary. Acceptable trade-off for tracking the upstream RustCrypto release.
  • chrono = "0.4" added (default-features off, clock and serde features) for the expires_at ISO 8601 date parsing and the "is this ack still active" check.

Install

Prebuilt binaries (Linux amd64 / arm64, macOS arm64, Windows amd64):

curl -LO https://github.com/robintra/perf-sentinel/releases/download/v0.5.17/perf-sentinel-linux-amd64
chmod +x perf-sentinel-linux-amd64
sudo mv perf-sentinel-linux-amd64 /usr/local/bin/perf-sentinel

Linux binaries are statically linked against musl and run on any distribution (Alpine, Debian, RHEL, Ubuntu any version) regardless of glibc version, and inside FROM scratch images.

From crates.io:

cargo install perf-sentinel --version 0.5.17

Docker:

docker run --rm -p 4317:4317 -p 4318:4318 \
  ghcr.io/robintra/perf-sentinel:0.5.17 watch --listen-address 0.0.0.0

Also available on Docker Hub: robintrassard/perf-sentinel:0.5.17.

Helm (chart 0.2.20 ships 0.5.17 as its appVersion default):

helm install perf-sentinel oci://ghcr.io/robintra/charts/perf-sentinel \
  --version 0.2.20 \
  --namespace observability --create-namespace

Verify the binary against SHA256SUMS.txt:

curl -LO https://github.com/robintra/perf-sentinel/releases/download/v0.5.17/SHA256SUMS.txt
sha256sum -c SHA256SUMS.txt --ignore-missing

Full diff: v0.5.16...v0.5.17