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.tomlfile 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 malformedexpires_atfails the run loud rather than silently widening the matched set. The loader caps file size at 16 MiB so a stray--acknowledgments /dev/zerocannot exhaust process memory.Finding.signature: Stringfield, 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 fromanalyze --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 originalFindingwith the matchingAcknowledgmentmetadata. Additive viaserde(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).inspectomits--show-acknowledgedbecause the TUI does not yet have a dedicated panel, the status footer surfaces the count. - SARIF properties extended with
acknowledged: true,acknowledgmentReason,acknowledgmentBy,acknowledgmentAton 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 thesanitize_sarif_filepathdiscipline so a hostileacknowledged_bycannot 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 = 0flips the gate from FAIL to PASS once acked. Theio_waste_ratio_maxrule is unaffected because it reads from raw spans (not findings), this asymmetry is documented indocs/ACKNOWLEDGMENTS.md. Acks are applied to both sides ofdiffso 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-startReport.warningssignal, and three additional rate / latency views aligned with the simulation-labverify-grafana-dashboardscenario. Single source of truth: the lab's previously distinct French overview atmanifests/grafana-dashboards/perf-sentinel-overview.jsonis replaced by a verbatim copy of this file, with a CI parity check. - 17 unit tests in
crates/sentinel-core/src/acknowledgments.rscovering 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 throughapply_to_reportcannot accumulate stale ack pairs across runs. - 6 e2e CLI tests in
crates/sentinel-cli/tests/e2e.rscovering 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) anddocs/FR/ACKNOWLEDGMENTS-FR.md(FR) with the full workflow, signature format, FAQ. Cross-references fromREADME.md/README-FR.md,docs/CONFIGURATION.md/ FR mirror, and a new "Investigating an unexpected ack" section indocs/RUNBOOK.md/ FR mirror.
Changed
pipeline::analyzepopulatesFinding.signatureat the end of detection via the sharedacknowledgments::enrich_with_signatures(&mut findings)helper. The daemon ingestion loop (daemon/event_loop.rs) does the same so live snapshots from/api/export/reportcarry signatures usable for ack matching. CLI Report-from-baseline paths (cmd_report --input <baseline.json>,cmd_diff --before,cmd_inspect --input <baseline.json>) callenrich_with_signaturesafter deserialization so pre-0.5.17 baselines (without thesignaturefield) still match acks correctly.emit_report_and_gatesignature now takes&mut Reportso the JSON / SARIF emit paths hideacknowledged_findingsvia a zero-copymem::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.tomlproduces identical output to 0.5.16, no error message, no warning. The newFinding.signaturefield is additive and does not alter existing JSON consumers because they ignore unknown fields. - HTML dashboard payload embeds
acknowledged_findingsonly when--show-acknowledgedis set onreport. 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.mdandREADME-FR.mdgain 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_statementsintegration). Each scenario ships a Mermaid architecture diagram, the exact inputs and outputs, the required configuration, and the gotchas that surfaced during validation.docs/CONFIGURATION.mdanddocs/FR/CONFIGURATION-FR.mddocument the file format, loading rules, and the no-glob-no-wildcard decision.docs/RUNBOOK.mdanddocs/FR/RUNBOOK-FR.mdadd an "Investigating an unexpected ack" section with the three-step diagnostic recipe (--no-acknowledgmentsto compare,--show-acknowledgedto surface metadata,git logfor the audit trail).docs/ACKNOWLEDGMENTS.mdanddocs/FR/ACKNOWLEDGMENTS-FR.mdare new dedicated docs covering the full workflow, signature anatomy, quality gate semantics, and FAQ (handling stale acks, no-glob-by-design,inspectand HTML limitations).
Dependencies
sha2 = "0.11.0"added as a direct dependency ofsentinel-corefor the canonical signature hash. The 0.11 line moved fromgeneric-arraytohybrid-array, so it does not unify with thesha2 0.10.xstill 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,clockandserdefeatures) for theexpires_atISO 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-sentinelLinux 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.17Docker:
docker run --rm -p 4317:4317 -p 4318:4318 \
ghcr.io/robintra/perf-sentinel:0.5.17 watch --listen-address 0.0.0.0Also 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-namespaceVerify 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-missingFull diff: v0.5.16...v0.5.17