Repository navigation
RFC: wire code-scanning alerts into the dispatch pipeline (close-loop remediation for the 11,785 real-finding estate surface) #369
Description
Context
A 2026-05-27 estate audit of code-scanning alerts (see hypatia#368 for the data) found:
- 19,509 open alerts across 325 of 328 active repos
- 7,724 (39.6%) were CSA001/CSA002/CSA003 self-echo (now suppressed at SARIF render time by fix(sarif): suppress code_scanning_alerts findings from SARIF output (close estate-wide self-echo) #368)
- 11,785 real findings remain — the actual surface this RFC targets
The dispatch infrastructure (PatternAnalyzer → TriangleRouter → FleetDispatcher → DispatchManifest → dispatch-runner.sh → rhodibot/sustainabot/automaton) is fed today from panic-attack scans landing in verisim-data. GitHub code-scanning alerts are not wired as a recipe-matchable scan source — code_scanning_alerts.ex returns advisory :escalate/:review findings with no fix_script linkage.
Goal
Close the loop: a code-scanning alert appearing in GitHub Security → an automatic PR opened by the gitbot fleet that remediates it (for the deterministic subset), or an advisory issue / dispatch (for the rest).
Real-finding shape (top 15 by count)
| count | rule_id | class |
|---|---|---|
| 1985 | hypatia/workflow_audit/unknown |
needs taxonomy work |
| 1762 | hypatia/migration_rules/deprecated_api |
API-specific recipes |
| 661 | hypatia/cicd_rules/banned_language_file |
delete / migrate |
| 464 | hypatia/workflow_audit/unpinned_action |
mechanical (SHA pin) |
| 436 | hypatia/security_errors/secret_detected |
case-by-case |
| 415 | scorecard/PinnedDependenciesID |
mechanical (SHA pin) |
| 401 | hypatia/structural_drift/SD007 |
mechanical (file move) |
| 308 | hypatia/scorecard/StaticAnalysis |
mechanical (add codeql.yml) |
| 290 | hypatia/structural_drift/SD009 |
mechanical (file move) |
| 276 | hypatia/code_safety/expect_in_hot_path |
Rust rewrite |
| 229 | hypatia/git_state/GS007 |
branch hygiene |
| 227 | hypatia/code_safety/zig_ptr_cast |
Zig rewrite |
| 223 | scorecard/TokenPermissionsID |
mechanical (perms) |
| 223 | hypatia/code_safety/unwrap_without_check |
Rust rewrite |
| 170 | hypatia/workflow_audit/missing_workflow |
mechanical (add reusable) |
Bolded rows (~2,287 of 11,785, 19%) are deterministic — same fix shape every time, no judgment call. They are the natural first vertical.
Proposed design
Layer 1: a new finding-source adapter (small)
Hypatia.Sources.CodeScanningAlerts — wraps Rules.CodeScanningAlerts.scan/2 to produce normalised findings in the panic-attack scan shape (same JSON contract that VerisimdbConnector.fetch_all_scans/0 reads). Findings carry :rule_id (e.g. hypatia/workflow_audit/unpinned_action) and :alert_number so dispatch knows which GitHub alert to dismiss on success.
Layer 2: recipe matcher coverage
Adds recipes for the 9 deterministic rules to data/verisim/recipes/:
recipe-missing-workflow-reusable.json— already implicitly hand-applied for julia-professional-registry; codifyrecipe-unpinned-action.json— needs the SHA pins catalog (already infixer/src/sha_pins.rs)recipe-codeql-language-actions.json— addcodeql.ymlwithlanguage: actionsrecipe-structural-drift-move.json—.machine_readable/STATE.a2ml→.machine_readable/6a2/STATE.a2mlrecipe-token-permissions.json— already exists (recipe-scorecard-token-permissions.json)recipe-pinned-dependencies.json— leans onfixer/src/sha_pins.rs
Recipe matcher gains a rule_id field for direct match (today it relies on fuzzy fingerprint matching from panic-attack).
Layer 3: dispatch enrichment
FleetDispatcher.dispatch_routed_action/1 learns to:
- Look up the alert by
alert_number, - After a successful PR merge, dismiss the alert as
false positivewith reason "auto-resolved by PR #X" (or let GitHub's auto-close-on-merge handle it where the path mapping is exact).
Layer 4: schedule
Per the user's intent ("estate with zero issues except pending gitbot arrival"):
- One Hypatia cycle scans the estate (already runs via
hypatia-scan-reusable.yml) - The new code-scanning source feeds findings into the existing triangle router
- Bots pick up dispatched manifest entries on their existing cadence
First vertical (smallest provable closed loop)
- Add
Hypatia.Sources.CodeScanningAlerts(Layer 1) — pure normalisation, no behaviour change - Add
recipe-missing-workflow-reusable.jsonand wireworkflow_audit/missing_workflowto it - Run the existing dispatch pipeline against julia-professional-registry as the canary
- Confirm a bot opens a PR equivalent to PR chore(deps): bump docker/setup-qemu-action from 3.0.0 to 3.7.0 #17 without human intervention
- Roll forward to
unpinned_action, thenscorecard/StaticAnalysis
Three rule types, ~942 alerts, ~8% of the real-finding surface closeable without further design.
Out of scope (this RFC)
- The 4,500-ish
workflow_audit/unknown+migration_rules/deprecated_apialerts — needs a taxonomy pass before recipes can be written. code_safety/*Rust/Zig rewrites — these benefit from a different bot (sustainabot or finishingbot) and a richer code-edit primitive.
Open questions for owner
- Confirm intent: should bot-opened PRs for these alerts auto-merge (mirror style), or always require owner review? Current bot config does owner-review by default.
- PR template: do we want a single "estate-CI-hygiene" PR per repo per sweep (bundled) or one per alert? Bundled is more humane to review; per-alert is easier to revert.
- Dismissal vocabulary:
false positive(auto-resolved) vswon't fix(when remediation chooses removal instead of fix)? Leaningfalse positivefor auto-merge wins, since the alert genuinely no longer applies after the PR lands.
Activity
hyperpolymath commentedon Sep 30, 2026
RULING D137 (2026-09-30T14:12Z) · scope: estate · basis: owner (direct answer, selector)
Recipe-matchable pipeline with fix_script linkage, dispatch-only behind D34's guard, piloted on ONE repo before the 11,785-finding fleet
surface: hyperpolymath/standards#787 (comment)
The open question in this issue is answered by the ruling above; future agents should act on it rather than re-ask.
hyperpolymath commentedon Sep 30, 2026
Consolidated into the roadmap tracker #886 during the 2026-09-30 issue sweep. The idea is kept there as a checklist item; reopen this issue when work starts.