Skip to content

silent-revert canary: the incident corpus misattributes the #2633 revert to a PR that never merged #2831

Description

@kyle-sexton

The silent-revert canary merged in #2808 ships an incident corpus that
misattributes one of the three incidents it exists to prove. The corpus is the
guard's own honesty proof — --verify-known-incidents replays it on every
push: main — so an incorrect row costs the guard exactly the credibility it
was built to earn.

The clearest evidence is that the guard already contradicts its own fixture.
Running the shipped detector on the incident commit prints the correct
attribution:

$ scripts/check-silent-revert.sh --commit cc58cbc53fbbb2cca68e071507b82d3e3ff896ff

  removed by   cc58cbc53  fix(repo-fleet-hygiene): report bare repos with live working trees (#2633)
  content from bfb66beb8  feat(repo-fleet-hygiene): add finding rollups and scalable handoff plans (#2644)
  lines lost   853  (threshold 200, window 40 commits)

  removed by   cc58cbc53  fix(repo-fleet-hygiene): report bare repos with live working trees (#2633)
  content from eda5ae5ed  feat(repo-fleet-hygiene): gather merge evidence via aliased GraphQL (#2642)
  lines lost   301  (threshold 200, window 40 commits)

while scripts/silent-revert-incidents.txt records the same commit as
#2633 dropped #2632's rollups (853 lines) -- unfiled until now.

Four defects

1. The named victim never merged. PR #2632 (fix(repo-fleet-hygiene): warn on ignored files in reclaimable worktrees) is CLOSED, not MERGED:
mergeCommit is null, mergedAt is null, it was closed unmerged at
2026-08-14T23:19:00Z, its head commit 2b9391be is not an ancestor of
origin/main, and its diff contains zero occurrences of the string rollup.
It cannot be the victim of anything.

2. The real victims are #2644 and #2642. The rollups came from
bfb66beb8 (#2644, merged 2026-08-15T00:47:26Z). The reverting squash
cc58cbc53 (#2633, merged 00:55:27Z) has bfb66beb8 as its single parent.
Attributing every line cc58cbc53 deleted to the commit git blame credits
it to:

culprit PR lines
bfb66beb8 #2644 — finding rollups and handoff plans 853
eda5ae5ed #2642 — aliased GraphQL merge evidence 301
(11 other commits, ≤4 lines each) 11
total 1165

1165 matches the squash's diffstat exactly
(6 files changed, 549 insertions(+), 1165 deletions(-)). The second victim
(#2642) went unmentioned in the corpus entirely, even though the shipped
detector reports it as a separate finding.

Corroboration in the tree:
plugins/repo-fleet-hygiene/skills/audit/scripts/audit-fleet.sh went 2178
lines with 8 graphql and 9 rollup occurrences at bfb66beb8, to 1700 lines
with zero of either at cc58cbc53, back to 2348 with both restored at
6f0a31109 (#2640, the hand restore, merged 01:23:38Z), and 2933 on current
origin/main.

3. The 853 figure is stated without saying what it measures. It is correct,
but it is a blame attribution, not a diffstat and not the culprit's additions.
The squash removed 1165 lines in total, and #2644's own squash commit added 942
(git diff --shortstat d55ffbf5 bfb66beb8). A reader who takes 853 for either
of those will not be able to reproduce it.

That 942 is itself a good illustration of why a number needs its measurement
attached: gh pr view 2644 --json additions reports 947, because the PR-level
count is three-dot against the merge base while the squash commit's diffstat is
two-dot against its parent, and main moved under the branch in between. Same
divergence on #2640+1281/−463 as a commit, 1269/451 as a PR.

4. The "unfiled until now" claim is false. Issue #2656
"repo-fleet-hygiene: bare-repo-with-working-tree ships on main with zero test
coverage after a stale-base squash and its fix", created 2026-08-15T02:19:57Z,
now CLOSED/COMPLETED — already documented this merge event, pinned to the same
commits, roughly 23 hours before #2808 merged. It filed it from the
test-coverage angle rather than as a silent revert, so the canary's genuine
contribution is detection speed and automation, not discovery — but the corpus
should not claim nobody had filed it.

A minor related inaccuracy, non-load-bearing: #2656 cites the collector as
plugins/repo-fleet-hygiene/scripts/audit-fleet.sh. The real path includes
skills/audit/. Worth not propagating.

Affected files

  • scripts/silent-revert-incidents.txt — the fires cc58cbc5… row and its
    preceding comment block
  • scripts/check-silent-revert.sh — the WHY THIS EXISTS header, the
    curated-marker-strings rejection paragraph, and the two calibration
    paragraphs that enumerate incident sizes
  • scripts/silent-revert-acknowledged.txt — the 6f0a31109 (fix(repo-fleet-hygiene): restore GraphQL merge evidence and rollups after #2633 #2640) row and
    its comment
  • .github/workflows/silent-revert-canary.yml — the header narrative

Fix

Name #2644 and #2642 as the victims, state that the 853/301 figures are blame
attributions against a single culprit rather than diffstat totals, replace the
"unfiled" claim with a citation of #2656, and use the correct audit-fleet.sh
path. The detector's behavior and thresholds must not change — this is a data
and narrative correction only, and --verify-known-incidents must still pass
against the unchanged shipped settings.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions