Skip to content

feat(rules): BP008 phantom required context + AM010 admin-merge eligibility#376

Merged
hyperpolymath merged 4 commits into
mainfrom
feat/bp008-phantom-ctx-and-am010
May 28, 2026
Merged

feat(rules): BP008 phantom required context + AM010 admin-merge eligibility#376
hyperpolymath merged 4 commits into
mainfrom
feat/bp008-phantom-ctx-and-am010

Conversation

@hyperpolymath
Copy link
Copy Markdown
Owner

Summary

  • BP008 (lib/rules/branch_protection.ex): walks the last N (default 5) commits on main, unions every observed check_run.name, and flags any required status-check context absent from that union. Severity :high, routes to :sustainabot.
  • AM010 (lib/rules/admin_merge_eligibility.ex): orthogonal to AM001-AM009 (which are title-shape). Given required_contexts, the phantom_contexts from BP008, and a PR's statusCheckRollup, returns {:eligible, "AM010"} when every required context is either passing or phantom.

Why

The 2026-05-28 affinescript binding sweep tried to auto-merge 14 PRs across 9 repos. Every affinescript PR sat in mergeStateStatus: BLOCKED with every visible check green, because spark-theatre-gate / SPARK Theatre Gate is in the repo's required_status_checks.contexts but no workflow emits it. Auto-merge can never satisfy a context that never runs; admin-merge was the only path.

This pattern is silent: nothing in the existing rules surfaced it. BP008 detects it from the API side; AM010 lets sustainabot's budget-resume sweep clear phantom-blocked PRs without needing per-PR title patterns.

Test plan

  • lib/rules/branch_protection.ex compiles clean
  • lib/rules/admin_merge_eligibility.ex compiles clean
  • AM010 8/8 tests pass (test/rules/admin_merge_eligibility_test.exs)
  • BP008 3/3 wiring tests pass (test/rules/branch_protection_test.exs)
  • BP008 returns [] cleanly without a token (matches existing convention)
  • BP008 wired into scan/2 facade

Follow-up

A separate hyperpolymath/affinescript issue will be filed to either remove spark-theatre-gate / SPARK Theatre Gate from required contexts or wire up its emitting workflow — owner decision.

🤖 Generated with Claude Code

…bility

Adds two paired rules to surface and remediate a class of stalled-auto-merge
discovered in the 2026-05-28 affinescript sweep.

BP008 (BranchProtection): walks the last N (default 5) commits on main,
unions every observed `check_run.name`, and flags any required status-check
context absent from that union. The empirical trigger:
`spark-theatre-gate / SPARK Theatre Gate` is required on
hyperpolymath/affinescript but no workflow emits it, so every PR sits in
mergeStateStatus=BLOCKED with all visible checks green. Severity :high,
routes to :sustainabot, returns [] cleanly without a token.

AM010 (AdminMergeEligibility): orthogonal to AM001-AM009 (title-shape),
this is a state recognizer. Given a PR's required-contexts, the phantom
set from BP008, and its statusCheckRollup, returns {:eligible, "AM010"}
when every required context is either passing or phantom. Lets the
budget-resume sweep clear phantom-blocked PRs without per-PR title
patterns.

8 AM010 tests + 3 BP008 wiring tests; both modules compile clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@hyperpolymath hyperpolymath enabled auto-merge (squash) May 28, 2026 13:30
@github-actions
Copy link
Copy Markdown

🔍 Hypatia Security Scan

Findings: 102 issues detected

Severity Count
🔴 Critical 0
🟠 High 0
🟡 Medium 102
View findings
[
  {
    "reason": "Issue in ci.yml",
    "type": "unknown",
    "file": "ci.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in ci.yml",
    "type": "unknown",
    "file": "ci.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in ci.yml",
    "type": "unknown",
    "file": "ci.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in ci.yml",
    "type": "unknown",
    "file": "ci.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in ci.yml",
    "type": "unknown",
    "file": "ci.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in ci.yml",
    "type": "unknown",
    "file": "ci.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in ci.yml",
    "type": "unknown",
    "file": "ci.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in ci.yml",
    "type": "unknown",
    "file": "ci.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in clusterfuzzlite.yml",
    "type": "unknown",
    "file": "clusterfuzzlite.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in clusterfuzzlite.yml",
    "type": "unknown",
    "file": "clusterfuzzlite.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  }
]

Powered by Hypatia Neurosymbolic CI/CD Intelligence

hyperpolymath and others added 2 commits May 28, 2026 14:35
…s PR's rollup

A context flagged phantom by BP008 derives that label from a sample of
the LAST N MAIN COMMITS. If THIS PR has any rollup entry for that
context (passing, failing, pending, in-progress), the context IS firing
on this PR — the BP008 main-branch sample was a false-negative for
this commit. Admin-merging on the basis of "BP008 says phantom" would
bypass that actual check.

Tighten the eligibility predicate: a context counts as
phantom-on-this-PR iff (BP008 phantom) AND (absent from rollup_names).
Any rollup entry — terminal or in-flight — collapses the phantom
classification for this commit and the PR falls through to the
standard "wait for it" / "not phantom only" path.

Tests added (6 new, 14/14 pass via standalone elixir):
- in-progress phantom-on-PR → not eligible
- queued phantom-on-PR → not eligible
- pending (lowercase) phantom-on-PR → not eligible
- all phantoms in-progress → set collapses to empty → not eligible
- FAILURE on phantom → ran and failed here → not eligible
- SUCCESS on phantom → passing → eligibility falls through correctly

Empirical safety: this prevents admin-merge from bypassing a
path-filtered workflow that happens to touch the path on THIS PR but
not on recent main commits. Closes the only practical Type 1 risk
identified in the AM010 design review.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown

🔍 Hypatia Security Scan

Findings: 102 issues detected

Severity Count
🔴 Critical 0
🟠 High 0
🟡 Medium 102
View findings
[
  {
    "reason": "Issue in ci.yml",
    "type": "unknown",
    "file": "ci.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in ci.yml",
    "type": "unknown",
    "file": "ci.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in ci.yml",
    "type": "unknown",
    "file": "ci.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in ci.yml",
    "type": "unknown",
    "file": "ci.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in ci.yml",
    "type": "unknown",
    "file": "ci.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in ci.yml",
    "type": "unknown",
    "file": "ci.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in ci.yml",
    "type": "unknown",
    "file": "ci.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in ci.yml",
    "type": "unknown",
    "file": "ci.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in clusterfuzzlite.yml",
    "type": "unknown",
    "file": "clusterfuzzlite.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in clusterfuzzlite.yml",
    "type": "unknown",
    "file": "clusterfuzzlite.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  }
]

Powered by Hypatia Neurosymbolic CI/CD Intelligence

@hyperpolymath hyperpolymath merged commit 524f754 into main May 28, 2026
38 checks passed
@hyperpolymath hyperpolymath deleted the feat/bp008-phantom-ctx-and-am010 branch May 28, 2026 13:46
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.

1 participant