Skip to content

audit.py branch-drift check false-positives on cherry-picked (patch-equivalent) promotion commits #336

Description

@ptr727

Context

Discovered while closing out HomeAutomation-Config #21 (conformance carry). The fleet audit reported:

DRIFT  branch: main carries content develop lacks (forward-sync needed)

and the issue carried a forward-sync task (task 4) on that basis. The forward-sync turned out to be a no-op: nothing on main was missing from develop. The finding was a false positive.

Root cause

spec/audit.py derives the finding from GitHub's three-dot compare (repos/{slug}/compare/develop...main) and treats any non-empty files[] as "main carries content develop lacks":

# trees are identical. Content is the signal - a develop...main compare with changed files means
# main carries content develop lacks (forward-sync needed); develop merely ahead is normal.
cmp = gh(f"repos/{slug}/compare/develop...main", ok404=True)

Three-dot compare lists files changed on main since the merge-base - it is blind to whether develop already carries equivalent content under different SHAs. HomeAutomation-Config's promotions #18/#20 landed via promote/* cherry-pick branches, so main holds cherry-picks (c5026d5, dcfcae0) of develop commits (d97f44d, 2ff1c53). The compare listed their files even though the content was already on develop before the audit ran.

Evidence from the repo:

$ git cherry origin/develop origin/main       # "-" = patch-equivalent already on develop
- c5026d5a393399e07c6b32a8a781e70cb04819fb
- dcfcae02780a8b1f6431b73352dbb0d99319884f

$ for f in CODESTYLE.md .github/workflows/test-pull-request.yml; do
    [ "$(git rev-parse origin/develop:$f)" = "$(git rev-parse origin/main:$f)" ] \
      && echo "$f: identical at both heads"; done
CODESTYLE.md: identical at both heads
.github/workflows/test-pull-request.yml: identical at both heads

Every file the compare reported is blob-identical at the two heads. Any repo whose promotion flow ever cherry-picks (rather than merging develop in verbatim) will re-trigger this finding on every audit until the next promotion happens to realign the merge-base.

Suggested fix

Post-filter the compare's files[] by blob equality at the two heads: for each path, fetch the blob SHA at develop and at main (contents API with ref, or one trees call per head) and drop paths whose blobs match - content develop already has is not "content develop lacks". Only the remainder justifies the DRIFT finding (and could be enumerated in the finding text, which would also make a residual false positive easy to spot downstream).

Patch-id equivalence (git cherry semantics) is the more precise commit-level test, but blob equality at the heads is sufficient for the content-level claim the finding makes, and is cheap over the REST API.

Impact

  • HomeAutomation-Config Improve setup instructions and documentation consistency #21 task 4 was authored (and worked) against a finding that had already been satisfied before the issue was filed; the downstream agent spent the effort proving the no-op instead.
  • The finding text ("N+ changed file(s)") does not name the files, so a downstream reader cannot cheaply see that the listed drift is cherry-pick noise.

No downstream action needed - #21 is closed with the forward-sync documented as a no-op; this is hub-side hardening only.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions