Skip to content

Reproducer test for #359: cquery rule inputs drop configuration_checksum#361

Merged
tinder-maxwellelliott merged 1 commit into
masterfrom
claude/reproducer-issue-359
May 22, 2026
Merged

Reproducer test for #359: cquery rule inputs drop configuration_checksum#361
tinder-maxwellelliott merged 1 commit into
masterfrom
claude/reproducer-issue-359

Conversation

@tinder-maxwellelliott
Copy link
Copy Markdown
Collaborator

Summary

Closes #359 (reproducer) — this PR is tests only, no behaviour change.

  • Adds 3 unit tests to BazelRuleTest pinning down the cquery configuration-invariance bug described in Configuration-aware hashing under --useCquery (parity with target-determinator) #359 at the lowest possible level — directly on BazelRule.ruleInputList() / BazelRule.digest(), no fixture workspace or live Bazel call needed.
  • The @Ignored test testCqueryRuleInputListDistinguishesConfigurationChecksum_reproducerForIssue359 documents the desired post-fix invariant. I verified locally that flipping the @Ignore off makes it fail with expected to not be equal to: <[//:dep]> — exactly the collapse the issue describes.
  • Two companion tests (*_currentBehaviourBuggy_issue359) lock in the current behaviour so CI stays green AND so we get a regression signal: if either ever starts failing, the @Ignore should be flipped off as part of the fix.

Why this is the right reproducer shape

The issue identifies cli/src/main/kotlin/com/bazel_diff/hash/RuleHasher.kt and cli/src/main/kotlin/com/bazel_diff/bazel/BazelRule.kt as the loss site — configuredRuleInputList.map { it.label } discards configuration_checksum. A unit test that builds two Build.Rule protos differing only in ConfiguredRuleInput.configuration_checksum and asserts that ruleInputList(useCquery=true) distinguishes them isolates the bug exactly at that code line. An E2E test using a real Bazel workspace + --platforms swap would also work but is far more fragile (platforms infra, Bazel-version assumptions) and isn't necessary to make the bug visible.

The companion tests also pin down a useful invariant for the fix: today BazelRule.digest(...) doesn't read configured_rule_input at all (see BazelRule.kt:14-26) — so a fix that just mixes configuration_checksum into the digest would also flip the third test.

Test plan

  • bazel test //cli:BazelRuleTest passes with the reproducer @ignore'd (5 tests, 1 ignored)
  • Verified the reproducer fails for the right reason: flipped @Ignore off locally → AssertionFailedError: expected to not be equal to: <[//:dep]>
  • Wait for CI matrix (ubuntu+macos × bazel 7/8/9) to confirm cross-version

🤖 Generated with Claude Code

…hecksum

Under --useCquery, BazelRule.ruleInputList() reads from configured_rule_input
but maps each entry to `.label` only, discarding `.configurationChecksum`.
Two configured graphs that share dep labels but differ in per-edge
configuration (cfg="exec" transitions, --platforms swap, --config=...,
--define toggling a select() in a dep) collapse to identical ruleInputList()
output, so RuleHasher cannot tell them apart and bazel-diff under cquery
reports an empty impacted set.

Three tests pin this down at the lowest level:

* testCqueryRuleInputListDistinguishesConfigurationChecksum_reproducerForIssue359
  -- @ignore'd reproducer asserting the desired post-fix invariant
  (inputsA != inputsB). Verified to fail today with
  "expected to not be equal to: <[//:dep]>".
* testCqueryRuleInputListCollapsesConfigurationChecksum_currentBehaviourBuggy_issue359
  -- pins the current (buggy) behaviour: both lists collapse to [//:dep].
* testBazelRuleDigestIgnoresConfigurationChecksum_currentBehaviourBuggy_issue359
  -- pins that BazelRule.digest() does not touch configured_rule_input at all.

The two `_currentBehaviourBuggy_*` tests keep CI green and give a
regression signal: if they ever start failing, the `@Ignore` on the
reproducer should be flipped off as part of the fix.

Refs #359

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@tinder-maxwellelliott tinder-maxwellelliott merged commit 781ba0e into master May 22, 2026
15 checks passed
@tinder-maxwellelliott tinder-maxwellelliott deleted the claude/reproducer-issue-359 branch May 22, 2026 13:52
tinder-maxwellelliott added a commit that referenced this pull request May 22, 2026
Under --useCquery, BazelRule.ruleInputList() previously folded each
ConfiguredRuleInput to its bare label via `.map { it.label }`, dropping
`configurationChecksum`. Two configured graphs that shared dep labels
but differed in per-edge configuration -- a `cfg = "exec"` transition
flip, a --platforms swap, a --config=... change, or a `--define`
toggling a select() inside a dep -- collapsed to identical
ruleInputList() output, so RuleHasher's transitive walk produced
identical digests and bazel-diff returned an empty impacted set under
cquery mode.

This change folds each dep edge's `configurationChecksum` into the
rule-input string using `|` -- a character that is invalid in a Bazel
label, so the encoding can never collide with a real input and survives
the existing `List<String>` return type. The full encoded string is
what gets mixed into RuleHasher's transitive hash, so two configured
graphs differing only by per-edge configuration now produce distinct
parent digests. RuleHasher splits on the separator to recover the bare
label for `allRulesMap` / `sourceDigests` lookups and dep tracking, so
the user-visible deps in the generated JSON stay clean.

The empty-checksum fallback (a known Bazel quirk where cquery's
`transitions=lite` output sometimes omits the checksum for an edge)
returns the bare label unchanged, preserving pre-#359 behaviour for
that path.

This is a hash-format change: hashes generated by this version are not
comparable to hashes from earlier versions under --useCquery, which is
the intended behaviour -- the old hashes were missing the
configuration signal.

Tests:
* Unignore the PR #361 reproducer
  (`testCqueryRuleInputListDistinguishesConfigurationChecksum_issue359`)
  and drop the two `_currentBehaviourBuggy_*` companions.
* Add `testCqueryRuleInputListEncodesLabelAndChecksum_issue359` to pin
  the on-the-wire encoding.
* Add `testCqueryRuleInputListEmptyChecksumFallsBackToBareLabel_issue359`
  to cover the Bazel-quirk fallback.
* Add `testNonCqueryRuleInputListIgnoresConfiguredRuleInput_issue359`
  to confirm the encoding does not leak into the non-cquery path.
* Add `testDecodeConfiguredRuleInputLabelRoundTrip_issue359` to pin the
  round-trip behaviour RuleHasher relies on.

This is the minimal symptom-fixing slice of #359 -- the parent target's
hash now reflects per-edge configuration changes, so the empty-impacted
set under cquery is gone. Full target-determinator parity (per-(label,
configuration) digest entries, `bazel config --output=json`
enumeration, empty-checksum inheritance from the depending target) is
intentionally out of scope here; those would change the on-disk JSON
schema and warrant a separate design discussion on the issue.

Refs #359, #361

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Configuration-aware hashing under --useCquery (parity with target-determinator)

1 participant