feat(rules): SD022 + SD023 — stale-path-after-rename + STATE.a2ml divergence#425
Merged
hyperpolymath merged 2 commits intoJun 2, 2026
Conversation
…ergence Adds two new structural-drift rules to catch the exact drift patterns surfaced by the 2026-06-02 estate sweep against JoshuaJewell/paint-type. ## SD022 — stale-path-after-rename (medium / trigger_intensive) When a source directory is renamed in a single commit, trailing-edge doc references frequently outlive the rename. Detection: enumerate real `src/*/` subdirs in the tree, scan docs (.md / .adoc / .a2ml / .contractile / .toml / .twasm) for `src/<dir>/` regex matches, flag any whose `<dir>` is not in the real-subdir set. Exemptions: - CHANGELOG.md (historical references are documentation, not drift) - third_party/ subtree (vendored, owned upstream) Recovery action: `sed -i s|src/<stale>|src/<new>|g` across the flagged file set. Identify <new> via `git log --diff-filter=R`. Empirical: caught 49 occurrences across 25 files on paint-type after PR #48 renamed src/ephapax → src/paint_core in the Cargo workspace but updated no docs. Manual sweep landed as paint-type#49. ## SD023 — STATE.a2ml divergence (medium) Some repos retain both legacy `.machine_readable/STATE.a2ml` and canonical `.machine_readable/6a2/STATE.a2ml`. When both exist, they MUST agree on `last-updated` — otherwise consumers (Hypatia, agents reading 6a2) see inconsistent reality. Detection: extract `last-updated` from each via regex matching both TOML (`last-updated = "..."`) and Scheme (`(last-updated "...")`) variants. Flag if both exist + dates disagree. Empirical: paint-type top-level STATE was 2026-06-01 / 22% completion; 6a2/STATE was 2026-05-11 / 10% completion. Unified in paint-type#49. ## Test coverage 7 new test cases: - SD022: positive case (ephapax→paint_core); CHANGELOG exemption; third_party/ exemption; empty src/ baseline - SD023: positive divergence; matching dates (no finding); only-one-file (no finding); Scheme-variant matching All tests use the same temporary-dir + git-init pattern as existing SD001-SD014 tests. ## Wired into scan/1 Both rules appended to the comprehensive scan pipeline. SD022 finds contribute trigger_intensive=true (one rename-drift hit predicts others); SD023 stays advisory. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
🔍 Hypatia Security ScanFindings: 146 issues detected
View findings[
{
"reason": "Action urin 21 JRE\n uses: actions/setup-java@be666c2fcd27 needs attention",
"type": "unpinned_action",
"file": "verify-proofs.yml",
"action": "pin_sha",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in ci.yml",
"type": "missing_timeout_minutes",
"file": "ci.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in ci.yml",
"type": "missing_timeout_minutes",
"file": "ci.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in ci.yml",
"type": "missing_timeout_minutes",
"file": "ci.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in ci.yml",
"type": "missing_timeout_minutes",
"file": "ci.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in ci.yml",
"type": "missing_timeout_minutes",
"file": "ci.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in ci.yml",
"type": "missing_timeout_minutes",
"file": "ci.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in ci.yml",
"type": "missing_timeout_minutes",
"file": "ci.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in ci.yml",
"type": "missing_timeout_minutes",
"file": "ci.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in clusterfuzzlite.yml",
"type": "missing_timeout_minutes",
"file": "clusterfuzzlite.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
}
]Powered by Hypatia Neurosymbolic CI/CD Intelligence |
🔍 Hypatia Security ScanFindings: 166 issues detected
View findings[
{
"reason": "Action urin 21 JRE\n uses: actions/setup-java@be666c2fcd27 needs attention",
"type": "unpinned_action",
"file": "verify-proofs.yml",
"action": "pin_sha",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in ci.yml",
"type": "missing_timeout_minutes",
"file": "ci.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in ci.yml",
"type": "missing_timeout_minutes",
"file": "ci.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in ci.yml",
"type": "missing_timeout_minutes",
"file": "ci.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in ci.yml",
"type": "missing_timeout_minutes",
"file": "ci.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in ci.yml",
"type": "missing_timeout_minutes",
"file": "ci.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in ci.yml",
"type": "missing_timeout_minutes",
"file": "ci.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in ci.yml",
"type": "missing_timeout_minutes",
"file": "ci.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in ci.yml",
"type": "missing_timeout_minutes",
"file": "ci.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in clusterfuzzlite.yml",
"type": "missing_timeout_minutes",
"file": "clusterfuzzlite.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
}
]Powered by Hypatia Neurosymbolic CI/CD Intelligence |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Two new structural-drift rules wired into
Hypatia.Rules.StructuralDrift.scan/1, addressing exactly the drift patterns surfaced by the 2026-06-02 estate sweep against JoshuaJewell/paint-type.src/<dir>/patterns where<dir>is not a real subdir. Exempts CHANGELOG.md (historical) + third_party/ (vendored).trigger_intensive: true(one drift hit predicts others)..machine_readable/STATE.a2mland.machine_readable/6a2/STATE.a2ml. Matcheslast-updatedin both TOML and Scheme variants.Empirical motivation
paint-type PR #48 renamed
src/ephapax/→src/paint_core/in the Cargo workspace, leaving 49 stale references across 25 docs. Top-level STATE.a2ml said 2026-06-01 / 22%; 6a2/STATE.a2ml said 2026-05-11 / 10%. Caught only by manual sweep (paint-type#49). These rules close that detection gap.Test plan
mix compile(verified via Code.string_to_quoted: both files parse clean)mix test test/structural_drift_test.exs— 7 new tests underdescribe "sd022_…"+describe "sd023_…"StructuralDrift.scan/1returns SD022+SD023 infindingswhen triggered