Skip to content

feat(release): score dependency floors and cargo features in semver-level - #2506

Draft
iunanua wants to merge 3 commits into
mainfrom
igor/versioning/semver-level-dep-and-feat
Draft

feat(release): score dependency floors and cargo features in semver-level#2506
iunanua wants to merge 3 commits into
mainfrom
igor/versioning/semver-level-dep-and-feat

Conversation

@iunanua

@iunanua iunanua commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

What does this PR do?

semver-level.sh combined cargo-semver-checks and cargo-public-api. Both read rustdoc and neither reads a manifest, so two semver-relevant manifest changes came out as patch:

  • a raised dependency requirement floor (http = "1""1.1"): every rustdoc signature is byte-identical, yet a consumer pinned to the old version can no longer resolve the crate — conventionally a minor;
  • an added cargo feature: cargo-semver-checks has no lint for an addition at all, and a feature adds no rustdoc item unless it happens to gate one.

Two passes are added, both reading the manifest through cargo metadata:

pass reports
2b) dependency requirement floors minor when the lowest version a requirement admits goes up
2c) cargo feature surface minor on an added feature; major on one removed or dropped from default

The second commit is a consequence of the first: build moves into the permissive PR-title type list, because scoring a dependency floor as minor would otherwise make build(deps): bump foo from 1.0 to 1.1 — the conventional title for a dependency change — fail the type rule.

The third commit is what lets CI reach any of it. detect-changes selected a crate only when a file under its own directory changed, so a PR editing just the root manifest's [workspace.dependencies] selected nothing: has_rust_changes came out false, both the semver-check and validate jobs were skipped, and every PR title was accepted — a docs: title included. Since this workspace declares dependencies version-only at the root and members inherit them with workspace = true, that is the ordinary shape of a floor raise here, which left the pass above unreachable from CI. semver-level.sh grows a --list-affected mode naming every member whose dependency requirements or feature surface moved between two revisions, and detect-changes adds those crates to the ones it finds by path.

Motivation

Reviewing release proposal #2482 surfaced libdd-capabilities proposed as patch, when #2350 had moved its http requirement from ^1 to the workspace entry at ^1.1. That is a minor, and nothing in the pipeline could see it: the version had moved into [workspace.dependencies], so even a textual diff of the crate's own Cargo.toml shows only { workspace = true } with no version in it.

Additional Notes

Points reviewers may want to weigh:

  • Read through cargo metadata, not Cargo.toml. That is what resolves { workspace = true } to the version the root manifest declares, and what surfaces the implicit feature an optional = true dependency creates.
  • Dependencies are keyed by .rename as well as name/kind/target. A crate aliasing two versions of one package emits an identical name, kind and target for both; keyed without the alias, the second matches the first's baseline requirement and an unchanged pair reads as a raise.
  • Exclusive bounds carry a flag, so >=1.2.3>1.2.3 is seen as the narrowing it is rather than comparing equal.
  • A raised major floor is capped at minor on purpose. Whether that forces the dependent to major is release-version-major-bumps.sh's decision, made with the dependency graph this script cannot see; max_level() lets it win from there.
  • The two passes stop at different points. 2b can only report minor, so minor ends it. 2c can report major, so it runs on until major — which matters for a crate with no library target, where cargo-semver-checks is skipped entirely and nothing else watches the feature table.
  • Feature removals are a backstop, not the primary check. For a library crate feature_missing and feature_not_enabled_by_default get there first; both were verified to fail the run rather than merely warn, using a two-crate repro against the pinned invocation.
  • Deliberately not scored: dev-dependencies, a widened requirement, a dependency added or removed outright, and changes to what a feature enables (the two *_enables_feature lints' job).

On the detection commit:

  • --list-affected lives in semver-level.sh rather than a script of its own, because it reuses manifest_facts_at_rev — now able to read the whole workspace in one extraction — so what the detector considers a manifest fact cannot drift from what the passes score. A detector considering fewer facts silently selects nothing and reports "no change", which is the failure this commit fixes; there are no shell tests to catch that drift. 19 lines are new, the 51 they lean on are shared.
  • The mode compares from git merge-base, matching the base...HEAD the changed-file search uses. Measured from the baseline tip instead, a branch behind the baseline reports every crate that moved on the baseline since the fork, putting another branch's changes on this one's report — and since scoring uses the tip, a feature added on the baseline would read as a removal, i.e. a spurious major.
  • Publishability stays the caller's business. The mode lists workspace members; detect-changes keeps its own publish filter, so a publish = false member such as libdd-agent-client shows up in the list and is dropped where that filter already lives.
  • Cost. A crate selected only by moved facts still gets the full treatment, cargo-semver-checks and cargo-public-api both building rustdoc, so a one-line root bump now costs ~12 of those instead of zero. That is deliberate: a changed floor can alter a crate's API through re-exports. If it bites, the cheap follow-up is a mode running only passes 2b/2c for those crates. Release-proposal PRs are unaffected — they carry skip-pr-title-semver-check, and each member's version is literal, so the path search already finds them.
  • The release path reports the same change rather than releasing for it. commits-since-release.sh selects a crate's commits with git log "$COMMIT_RANGE" -- "$CRATE_PATH", so a root-only floor raise leaves every inheriting crate with no commits and release-version-bumps.sh defers it. That is the right outcome, not a second instance of the bug above: the crate's code is unchanged, the requirement its published version states is still true of that code, and requirements are minimums, so a consumer combining it with a freshly published sibling that asks for the raised floor resolves the newer dependency anyway. Deferring moves neither the version nor the tag, so the raise stays in range and the crate's next release is still scored a minor for it — late, not wrong — while the case where a crate's code does need the raised version always arrives with a change to a file of its own, which the path search already finds. What is missing there is only the saying so: a deferred crate is recorded as level none and reads as "nothing happened". A follow-up reports those moves at the deferral point instead of releasing 12 crates that needed nothing.

Verified on a one-line root bump of bytes from 1.11 to 1.12 (12 members inherit the entry):

before after
crates selected 0, both jobs skipped exactly the 12 inheritors
+ a feature added to one crate that crate, by path same, plus the 12
baseline unchanged none

Both manifest passes produce byte-identical output after the field shift in the shared reader (bytes (normal): ^1.11 -> ^1.12; Cargo feature added / added: new-thing), run under RUSTUP_TOOLCHAIN=1.92.0 as the workflow does. shellcheck on the script and on the extracted run: block (actionlint's -e SC2086 profile) reports nothing that was not already there.

🤖 Generated with Claude Code

iunanua and others added 2 commits September 10, 2026 10:00
…evel

semver-level.sh combined cargo-semver-checks and cargo-public-api, which both
read rustdoc and neither of which reads a manifest. Two semver-relevant
manifest changes therefore came out as patch:

- a raised dependency requirement floor (`http = "1"` -> `"1.1"`), after which
  a consumer pinned to the old version can no longer resolve this crate;
- an added cargo feature, for which cargo-semver-checks has no lint at all and
  which adds no rustdoc item unless it happens to gate one.

Add two passes that read both facts through `cargo metadata`, so a requirement
behind `{ workspace = true }` is compared as the version it resolves to and the
implicit feature of an `optional = true` dependency is counted. Requirements
are keyed by `.rename` as well as name, kind and target, so a crate aliasing
two versions of one package does not match the second alias against the first
alias's baseline. Exclusive bounds carry a flag, so `>=1.2.3` -> `>1.2.3` is
seen as the narrowing it is.

Feature removals and default-set removals are scored as a backstop: for a
library crate cargo-semver-checks gets there first, but for a crate with no
library target it is skipped entirely and nothing else would notice.

A raised major floor is capped at minor here on purpose --
release-version-major-bumps.sh owns that decision and max_level() lets it win.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
semver-level.sh now scores a raised dependency requirement floor as a minor, so
`build(deps): bump foo from 1.0 to 1.1` -- the conventional title for a
dependency change -- would start failing the PR type rule. Conventional Commits
defines `build` as changes to the build system or external dependencies, so a
dependency bump under its own type has to be allowed to be a minor. Both
`build:` commits in the last six months raised a real floor.

ci/docs/style/test stay restricted; none of them raised a non-dev dependency
floor over the same period. The breaking-change rule is untouched, so a `build`
PR that breaks the API still needs `build!:`.

Also correct the two messages that described the restriction as covering "API
changes" only, now that a level can come from a manifest change with no API
delta at all.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@datadog-datadog-prod-us1-2

datadog-datadog-prod-us1-2 Bot commented Sep 11, 2026

Copy link
Copy Markdown

Tests

All CI checks and tests passed.

🎉 All green!

🧪 All tests passed
❄️ No new flaky tests detected

🎯 Code Coverage (details)
Patch Coverage: 100.00%
Overall Coverage: 77.74% (-0.04%)

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: c49fb4f | Docs | View more details | Give us feedback!

@dd-octo-sts

dd-octo-sts Bot commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

Artifact Size Benchmark Report

aarch64-alpine-linux-musl
Artifact Baseline Commit Change
/aarch64-alpine-linux-musl/lib/libdatadog_profiling.so 8.96 MB 8.96 MB 0% (0 B) 👌
/aarch64-alpine-linux-musl/lib/libdatadog_profiling.a 95.57 MB 95.57 MB 0% (0 B) 👌
aarch64-unknown-linux-gnu
Artifact Baseline Commit Change
/aarch64-unknown-linux-gnu/lib/libdatadog_profiling.so 12.10 MB 12.10 MB 0% (0 B) 👌
/aarch64-unknown-linux-gnu/lib/libdatadog_profiling.a 106.92 MB 106.92 MB 0% (0 B) 👌
libdatadog-x64-windows
Artifact Baseline Commit Change
/libdatadog-x64-windows/debug/dynamic/datadog_profiling_ffi.dll 28.91 MB 28.91 MB 0% (0 B) 👌
/libdatadog-x64-windows/debug/dynamic/datadog_profiling_ffi.lib 96.08 KB 96.08 KB 0% (0 B) 👌
/libdatadog-x64-windows/debug/dynamic/datadog_profiling_ffi.pdb 191.08 MB 191.08 MB 0% (0 B) 👌
/libdatadog-x64-windows/debug/static/datadog_profiling_ffi.lib 810.01 MB 810.01 MB 0% (0 B) 👌
/libdatadog-x64-windows/release/dynamic/datadog_profiling_ffi.dll 9.65 MB 9.65 MB 0% (0 B) 👌
/libdatadog-x64-windows/release/dynamic/datadog_profiling_ffi.lib 96.08 KB 96.08 KB 0% (0 B) 👌
/libdatadog-x64-windows/release/dynamic/datadog_profiling_ffi.pdb 27.37 MB 27.37 MB 0% (0 B) 👌
/libdatadog-x64-windows/release/static/datadog_profiling_ffi.lib 55.31 MB 55.31 MB 0% (0 B) 👌
libdatadog-x86-windows
Artifact Baseline Commit Change
/libdatadog-x86-windows/debug/dynamic/datadog_profiling_ffi.dll 25.26 MB 25.26 MB 0% (0 B) 👌
/libdatadog-x86-windows/debug/dynamic/datadog_profiling_ffi.lib 97.58 KB 97.58 KB 0% (0 B) 👌
/libdatadog-x86-windows/debug/dynamic/datadog_profiling_ffi.pdb 196.30 MB 196.30 MB -0% (-8.00 KB) 👌
/libdatadog-x86-windows/debug/static/datadog_profiling_ffi.lib 795.90 MB 795.90 MB 0% (0 B) 👌
/libdatadog-x86-windows/release/dynamic/datadog_profiling_ffi.dll 7.46 MB 7.46 MB 0% (0 B) 👌
/libdatadog-x86-windows/release/dynamic/datadog_profiling_ffi.lib 97.58 KB 97.58 KB 0% (0 B) 👌
/libdatadog-x86-windows/release/dynamic/datadog_profiling_ffi.pdb 29.44 MB 29.44 MB 0% (0 B) 👌
/libdatadog-x86-windows/release/static/datadog_profiling_ffi.lib 52.22 MB 52.22 MB 0% (0 B) 👌
x86_64-alpine-linux-musl
Artifact Baseline Commit Change
/x86_64-alpine-linux-musl/lib/libdatadog_profiling.a 85.61 MB 85.61 MB 0% (0 B) 👌
/x86_64-alpine-linux-musl/lib/libdatadog_profiling.so 9.99 MB 9.99 MB 0% (0 B) 👌
x86_64-unknown-linux-gnu
Artifact Baseline Commit Change
/x86_64-unknown-linux-gnu/lib/libdatadog_profiling.a 101.52 MB 101.52 MB 0% (0 B) 👌
/x86_64-unknown-linux-gnu/lib/libdatadog_profiling.so 12.20 MB 12.20 MB 0% (0 B) 👌

@pr-commenter

pr-commenter Bot commented Sep 11, 2026

Copy link
Copy Markdown

Benchmarks

Comparison

Benchmark execution time: 2026-09-11 12:05:50

Comparing candidate commit c49fb4f in PR branch igor/versioning/semver-level-dep-and-feat with baseline commit 132842f in branch main.

📊 Benchmarking dashboard

Found 19 performance improvements and 5 performance regressions! Performance is the same for 132 metrics, 0 unstable metrics.

Explanation

This is an A/B test comparing a candidate commit's performance against that of a baseline commit. Performance changes are noted in the tables below as:

  • 🟩 = significantly better candidate vs. baseline
  • 🟥 = significantly worse candidate vs. baseline

We compute a confidence interval (CI) over the relative difference of means between metrics from the candidate and baseline commits, considering the baseline as the reference.

If the CI is entirely outside the configured SIGNIFICANT_IMPACT_THRESHOLD (or the deprecated UNCONFIDENCE_THRESHOLD), the change is considered significant.

Feel free to reach out to #apm-benchmarking-platform on Slack if you have any questions.

More details about the CI and significant changes

You can imagine this CI as a range of values that is likely to contain the true difference of means between the candidate and baseline commits.

CIs of the difference of means are often centered around 0%, because often changes are not that big:

---------------------------------(------|---^--------)-------------------------------->
                              -0.6%    0%  0.3%     +1.2%
                                 |          |        |
         lower bound of the CI --'          |        |
sample mean (center of the CI) -------------'        |
         upper bound of the CI ----------------------'

As described above, a change is considered significant if the CI is entirely outside the configured SIGNIFICANT_IMPACT_THRESHOLD (or the deprecated UNCONFIDENCE_THRESHOLD).

For instance, for an execution time metric, this confidence interval indicates a significantly worse performance:

----------------------------------------|---------|---(---------^---------)---------->
                                       0%        1%  1.3%      2.2%      3.1%
                                                  |   |         |         |
       significant impact threshold --------------'   |         |         |
                      lower bound of CI --------------'         |         |
       sample mean (center of the CI) --------------------------'         |
                      upper bound of CI ----------------------------------'

scenario:msgpack_decoder::v05/high_sharing/2000

  • 🟩 execution_time [-110.737µs; -109.662µs] or [-6.641%; -6.577%]
  • 🟩 throughput [+84461.287op/s; +85312.488op/s] or [+7.042%; +7.113%]

scenario:otlp/e2e_json/1x1000

  • 🟥 execution_time [+355.777µs; +361.796µs] or [+8.846%; +8.996%]

scenario:otlp/encode_json/1x1000

  • 🟥 execution_time [+378.663µs; +379.473µs] or [+22.744%; +22.793%]

scenario:otlp/encode_protobuf/1x1000

  • 🟩 execution_time [-54.488µs; -54.150µs] or [-4.891%; -4.861%]

scenario:vec_map/as_deduped_map/already_deduped/8

  • 🟩 execution_time [-0.607ns; -0.600ns] or [-4.186%; -4.144%]

scenario:vec_map/as_deduped_map/needs_dedup_1_in_10/8

  • 🟩 execution_time [-18.947ns; -18.706ns] or [-5.051%; -4.987%]

scenario:vec_map/as_deduped_map/needs_dedup_1_in_4/8

  • 🟩 execution_time [-17.860ns; -17.634ns] or [-4.293%; -4.239%]

scenario:vec_map/contains_key/128

  • 🟩 execution_time [-1.150µs; -1.135µs] or [-7.309%; -7.219%]
  • 🟩 throughput [+633332.850op/s; +641617.168op/s] or [+7.783%; +7.884%]

scenario:vec_map/contains_key/16

  • 🟩 execution_time [-25.052ns; -24.614ns] or [-9.838%; -9.666%]
  • 🟩 throughput [+6730035.848op/s; +6850592.516op/s] or [+10.710%; +10.902%]

scenario:vec_map/contains_key/64

  • 🟩 execution_time [-329.390ns; -325.073ns] or [-7.789%; -7.687%]
  • 🟩 throughput [+1260904.711op/s; +1278111.919op/s] or [+8.331%; +8.445%]

scenario:vec_map/contains_key/8

  • 🟩 execution_time [-3.730ns; -3.550ns] or [-4.993%; -4.752%]
  • 🟩 throughput [+5351689.916op/s; +5612593.546op/s] or [+4.997%; +5.241%]

scenario:vec_map/get_hit/16

  • 🟩 execution_time [-35.410ns; -35.136ns] or [-15.010%; -14.894%]
  • 🟩 throughput [+11879457.280op/s; +11967056.486op/s] or [+17.515%; +17.644%]

scenario:vec_map/get_hit/8

  • 🟩 execution_time [-10.965ns; -10.908ns] or [-16.886%; -16.799%]
  • 🟩 throughput [+24882800.311op/s; +25025917.310op/s] or [+20.197%; +20.313%]

scenario:vec_map/get_miss/128

  • 🟩 execution_time [-4.617ns; -3.946ns] or [-5.691%; -4.864%]

scenario:vec_map/get_miss/16

  • 🟥 execution_time [+18.057ns; +18.416ns] or [+191.673%; +195.479%]

scenario:vec_map/get_miss/64

  • 🟥 execution_time [+22.072ns; +22.258ns] or [+76.804%; +77.450%]

scenario:vec_map/get_miss/8

  • 🟥 execution_time [+10.969ns; +11.194ns] or [+145.850%; +148.833%]

Benchmark execution time: 2026-09-11 12:01:12

Comparing candidate commit c49fb4f in PR branch igor/versioning/semver-level-dep-and-feat with baseline commit 132842f in branch main.

📊 Benchmarking dashboard

Found 1 performance improvements and 20 performance regressions! Performance is the same for 144 metrics, 11 unstable metrics.

Explanation

This is an A/B test comparing a candidate commit's performance against that of a baseline commit. Performance changes are noted in the tables below as:

  • 🟩 = significantly better candidate vs. baseline
  • 🟥 = significantly worse candidate vs. baseline

We compute a confidence interval (CI) over the relative difference of means between metrics from the candidate and baseline commits, considering the baseline as the reference.

If the CI is entirely outside the configured SIGNIFICANT_IMPACT_THRESHOLD (or the deprecated UNCONFIDENCE_THRESHOLD), the change is considered significant.

Feel free to reach out to #apm-benchmarking-platform on Slack if you have any questions.

More details about the CI and significant changes

You can imagine this CI as a range of values that is likely to contain the true difference of means between the candidate and baseline commits.

CIs of the difference of means are often centered around 0%, because often changes are not that big:

---------------------------------(------|---^--------)-------------------------------->
                              -0.6%    0%  0.3%     +1.2%
                                 |          |        |
         lower bound of the CI --'          |        |
sample mean (center of the CI) -------------'        |
         upper bound of the CI ----------------------'

As described above, a change is considered significant if the CI is entirely outside the configured SIGNIFICANT_IMPACT_THRESHOLD (or the deprecated UNCONFIDENCE_THRESHOLD).

For instance, for an execution time metric, this confidence interval indicates a significantly worse performance:

----------------------------------------|---------|---(---------^---------)---------->
                                       0%        1%  1.3%      2.2%      3.1%
                                                  |   |         |         |
       significant impact threshold --------------'   |         |         |
                      lower bound of CI --------------'         |         |
       sample mean (center of the CI) --------------------------'         |
                      upper bound of CI ----------------------------------'

scenario:alloc_free/system/4096

  • 🟥 execution_time [+15.054ns; +15.252ns] or [+16.549%; +16.767%]

scenario:credit_card/is_card_number/x371413321323331

  • 🟥 execution_time [+725.791ns; +728.278ns] or [+12.677%; +12.720%]
  • 🟥 throughput [-19714337.501op/s; -19646611.237op/s] or [-11.287%; -11.248%]

scenario:credit_card/is_card_number_no_luhn/x371413321323331

  • 🟥 execution_time [+727.916ns; +730.504ns] or [+12.715%; +12.761%]
  • 🟥 throughput [-19771670.971op/s; -19701856.725op/s] or [-11.319%; -11.279%]

scenario:datadog_sample_span/service_rule_not_matching/wall_time

  • 🟥 execution_time [+5.535ns; +5.624ns] or [+4.168%; +4.235%]

scenario:no_profiler/short_circuit/4096

  • 🟥 execution_time [+6.495ns; +6.668ns] or [+6.638%; +6.815%]

scenario:normalization/normalize_name/normalize_name/Too-Long-.Too-Long-.Too-Long-.Too-Long-.Too-Long-.Too-Lo...

  • 🟥 execution_time [+18.924µs; +19.117µs] or [+10.159%; +10.262%]
  • 🟥 throughput [-499706.668op/s; -494919.605op/s] or [-9.309%; -9.219%]

scenario:normalization/normalize_name/normalize_name/bad-name

  • 🟥 execution_time [+1.218µs; +1.260µs] or [+6.899%; +7.132%]
  • 🟥 throughput [-3770383.646op/s; -3650949.931op/s] or [-6.658%; -6.447%]

scenario:normalization/normalize_name/normalize_name/good

  • 🟥 execution_time [+1.199µs; +1.234µs] or [+12.144%; +12.500%]
  • 🟥 throughput [-11251015.456op/s; -10955690.975op/s] or [-11.107%; -10.816%]

scenario:normalization/normalize_service/normalize_service/A0000000000000000000000000000000000000000000000000...

  • 🟥 execution_time [+36.054µs; +36.649µs] or [+7.227%; +7.347%]
  • 🟥 throughput [-137336.013op/s; -135008.060op/s] or [-6.851%; -6.735%]

scenario:normalization/normalize_service/normalize_service/Test Conversion 0f Weird !@#$%^&**() Characters

  • 🟥 execution_time [+21.218µs; +21.317µs] or [+12.542%; +12.600%]
  • 🟥 throughput [-661632.135op/s; -658526.019op/s] or [-11.194%; -11.141%]

scenario:profiler_attached/slow_path_system/4096

  • 🟥 execution_time [+8.218ns; +8.389ns] or [+5.597%; +5.714%]

scenario:sql/obfuscate_sql_string

  • 🟩 execution_time [-12.950µs; -12.661µs] or [-4.419%; -4.320%]

scenario:trace_buffer/2_senders/no_delay

  • 🟥 execution_time [+108.789µs; +125.182µs] or [+7.057%; +8.121%]
  • 🟥 throughput [-88302.320op/s; -76727.557op/s] or [-7.557%; -6.566%]

Unstable benchmarks

These benchmarks have a confidence interval too wide to call a change; treat them as noise rather than signal.

scenario:datadog_sample_span/parent_not_sampled_short_circuit/allocated_bytes

  • unstable execution_time [-0.000ns; +0.000ns] or [+553.427%; -554.650%]

scenario:datadog_sample_span/parent_sampled_short_circuit/allocated_bytes

  • unstable execution_time [-0.000ns; +0.000ns] or [+553.234%; -554.559%]

scenario:flagevaluation_evp/coalescer/typical/100flags_50users_10fields

  • unstable execution_time [-10441.033ns; +10115.063ns] or [-5.586%; +5.411%]

scenario:glob_matcher/ascii_case_insensitive_match/allocated_bytes

  • unstable execution_time [-0.000ns; +0.000ns] or [+549.614%; -552.863%]

scenario:glob_matcher/ascii_exact_match/allocated_bytes

  • unstable execution_time [-0.000ns; +0.000ns] or [+547.973%; -552.097%]

scenario:glob_matcher/ascii_exact_miss/allocated_bytes

  • unstable execution_time [-0.000ns; +0.000ns] or [+565.977%; -560.582%]

scenario:glob_matcher/ascii_wildcard_backtrack_match/allocated_bytes

  • unstable execution_time [-0.000ns; +0.000ns] or [+551.902%; -553.934%]

scenario:glob_matcher/ascii_wildcard_heavy_backtrack/allocated_bytes

  • unstable execution_time [-0.000ns; +0.000ns] or [+555.735%; -555.735%]

scenario:glob_matcher/ascii_wildcard_question_match/allocated_bytes

  • unstable execution_time [-0.000ns; +0.000ns] or [+545.718%; -551.046%]

scenario:glob_matcher/ascii_wildcard_star_match/allocated_bytes

  • unstable execution_time [-0.000ns; +0.000ns] or [+554.964%; -555.372%]

scenario:glob_matcher/star_short_circuit/allocated_bytes

  • unstable execution_time [-0.000ns; +0.000ns] or [+555.481%; -555.615%]

Candidate

Omitted due to size.

Baseline

Omitted due to size.

detect-changes selected a crate only when a file under its own directory
changed, so a PR editing just the root manifest's [workspace.dependencies]
selected nothing: has_rust_changes came out false and both the semver-check
and validate jobs were skipped, leaving any PR title accepted. Since this
workspace declares dependencies version-only at the root and members inherit
them with `workspace = true`, that is the ordinary shape of a floor raise
here, and the level semver-level.sh scores for it -- a minor -- was
unreachable from CI.

semver-level.sh grows a --list-affected mode naming every member whose
dependency requirements or feature surface moved between two revisions, and
detect-changes adds those crates to the ones it finds by path. It reuses
manifest_facts_at_rev, now able to read the whole workspace in one
extraction, so the facts the detector considers cannot drift from the facts
the passes score -- a detector that considered fewer would silently reselect
nothing.

The mode compares from `git merge-base`, matching the `base...HEAD` the
changed-file search uses: measured from the baseline tip instead, a branch
behind it reports every crate that moved on the baseline since the fork,
putting another branch's changes on this one's report.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant