ci: restrict abi-drift + zig-test cartridge loops to PR-changed cartridges#147
Merged
Merged
Conversation
Both workflows currently sweep every cartridge under cartridges/* and
fail the PR check if any single one fails. With ~66 cartridges in the
abi-drift allowlist and ~73 in zig-test, a PR touching one cartridge
gets gated by unrelated breakage in others (e.g. browser-mcp and
orchestrator-lsp-mcp Zig failures, container-mcp/git-mcp/queues-mcp/
vordr-mcp ABI drift) that has been sitting on main for weeks. This
makes every cartridge-touching PR look "blocked" when it isn't.
Constrain the per-cartridge loops to the intersection of:
(1) the existing allowlist / discovery, and
(2) cartridges with any file changed under cartridges/<name>/** in
this PR's diff (origin/<base>...HEAD).
On `push: main` events the full sweep is preserved, so cross-cutting
drift is still caught at trunk — this is purely a PR-time false-
positive fix, not a relaxation of the gate.
Both workflows now also `actions/checkout` with `fetch-depth: 0` so the
`git diff origin/<base>...HEAD` can resolve. An empty changed-set on a
PR (which the `paths:` filter shouldn't allow anyway, but be defensive)
emits a `::notice::` and exits 0 instead of going red on nothing.
abi-drift: new "Restrict to cartridges changed in this PR" step
filters steps.discover.outputs.carts; the verify loop picks either
steps.filter.outputs.carts (PR) or steps.discover.outputs.carts (push).
zig-test: new "Determine cartridges to test" step writes the in-scope
set once; the FFI-tests and shared-library-build loops both read it.
Catalogue tests (cd ffi/zig && zig build test) and the readiness step
still run on every invocation — those test the cross-cartridge plumbing
and must always go.
This is a follow-up to PR #146's CI investigation; unblocks future
single-cartridge PRs from inheriting unrelated breakage. Aspect tests
(tests/aspect_tests.sh) use a different shape — they assert global
invariants across the whole tree — so a "changed-files" filter doesn't
fit them cleanly. Leaving aspect alone in this PR; can revisit with a
baseline-aware ratchet if needed.
So this PR's own workflow change actually runs the workflow. abi-drift.yml already includes itself in `paths:` — apply the same convention to zig-test.yml.
🔍 Hypatia Security ScanFindings: 244 issues detected
View findings[
{
"reason": "Stale AI session file -- delete",
"type": "stale",
"file": "GEMINI.md",
"action": "delete",
"rule_module": "root_hygiene",
"severity": "medium"
},
{
"reason": "Issue in quality.yml",
"type": "missing_workflow",
"file": "quality.yml",
"action": "create",
"rule_module": "workflow_audit",
"severity": "high"
},
{
"reason": "Issue in security-policy.yml",
"type": "missing_workflow",
"file": "security-policy.yml",
"action": "create",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Action hyperpolymath/standards/.github/workflows/governance-reusable.yml@main needs attention",
"type": "unpinned_action",
"file": "governance.yml",
"action": "pin_sha",
"rule_module": "workflow_audit",
"severity": "high"
},
{
"reason": "TypeScript file detected -- banned language",
"type": "banned_language_file",
"file": "/home/runner/work/boj-server/boj-server/cartridges/sanctify-mcp/adapter/mod.ts",
"action": "flag",
"rule_module": "cicd_rules",
"severity": "critical"
},
{
"reason": "TypeScript file detected -- banned language",
"type": "banned_language_file",
"file": "/home/runner/work/boj-server/boj-server/cartridges/academic-workflow-mcp/adapter/mod.ts",
"action": "flag",
"rule_module": "cicd_rules",
"severity": "critical"
},
{
"reason": "TypeScript file detected -- banned language",
"type": "banned_language_file",
"file": "/home/runner/work/boj-server/boj-server/cartridges/fireflag-mcp/adapter/mod.ts",
"action": "flag",
"rule_module": "cicd_rules",
"severity": "critical"
},
{
"reason": "TypeScript file detected -- banned language",
"type": "banned_language_file",
"file": "/home/runner/work/boj-server/boj-server/cartridges/ephapax-mcp/adapter/mod.ts",
"action": "flag",
"rule_module": "cicd_rules",
"severity": "critical"
},
{
"reason": "TypeScript file detected -- banned language",
"type": "banned_language_file",
"file": "/home/runner/work/boj-server/boj-server/cartridges/bofig-mcp/adapter/mod.ts",
"action": "flag",
"rule_module": "cicd_rules",
"severity": "critical"
},
{
"reason": "TypeScript file detected -- banned language",
"type": "banned_language_file",
"file": "/home/runner/work/boj-server/boj-server/cartridges/hesiod-mcp/adapter/mod.ts",
"action": "flag",
"rule_module": "cicd_rules",
"severity": "critical"
}
]Powered by Hypatia Neurosymbolic CI/CD Intelligence |
…ll sweep
The previous refactor used:
CARTS: ${{ github.event_name == 'pull_request' && steps.filter.outputs.carts || steps.discover.outputs.carts }}
GitHub Actions expressions short-circuit JavaScript-style: when
steps.filter.outputs.carts is an EMPTY STRING (which is exactly the
intended PR-with-no-cartridge-changes case), the expression treats it
as falsy and falls through to steps.discover.outputs.carts — the
full 66-cartridge allowlist. That's why PR #147 (touches only
.github/workflows/*) still reported drift in container-mcp / git-mcp /
queues-mcp / vordr-mcp: the filter worked correctly but its empty
output was discarded.
Replace the two-step filter+ternary pattern with one always-correct
step (id: scope) that handles both PR and push internally and writes
a single output. Mirrors what zig-test.yml already does.
🔍 Hypatia Security ScanFindings: 244 issues detected
View findings[
{
"reason": "Stale AI session file -- delete",
"type": "stale",
"file": "GEMINI.md",
"action": "delete",
"rule_module": "root_hygiene",
"severity": "medium"
},
{
"reason": "Issue in quality.yml",
"type": "missing_workflow",
"file": "quality.yml",
"action": "create",
"rule_module": "workflow_audit",
"severity": "high"
},
{
"reason": "Issue in security-policy.yml",
"type": "missing_workflow",
"file": "security-policy.yml",
"action": "create",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Action hyperpolymath/standards/.github/workflows/governance-reusable.yml@main needs attention",
"type": "unpinned_action",
"file": "governance.yml",
"action": "pin_sha",
"rule_module": "workflow_audit",
"severity": "high"
},
{
"reason": "TypeScript file detected -- banned language",
"type": "banned_language_file",
"file": "/home/runner/work/boj-server/boj-server/cartridges/sanctify-mcp/adapter/mod.ts",
"action": "flag",
"rule_module": "cicd_rules",
"severity": "critical"
},
{
"reason": "TypeScript file detected -- banned language",
"type": "banned_language_file",
"file": "/home/runner/work/boj-server/boj-server/cartridges/academic-workflow-mcp/adapter/mod.ts",
"action": "flag",
"rule_module": "cicd_rules",
"severity": "critical"
},
{
"reason": "TypeScript file detected -- banned language",
"type": "banned_language_file",
"file": "/home/runner/work/boj-server/boj-server/cartridges/fireflag-mcp/adapter/mod.ts",
"action": "flag",
"rule_module": "cicd_rules",
"severity": "critical"
},
{
"reason": "TypeScript file detected -- banned language",
"type": "banned_language_file",
"file": "/home/runner/work/boj-server/boj-server/cartridges/ephapax-mcp/adapter/mod.ts",
"action": "flag",
"rule_module": "cicd_rules",
"severity": "critical"
},
{
"reason": "TypeScript file detected -- banned language",
"type": "banned_language_file",
"file": "/home/runner/work/boj-server/boj-server/cartridges/bofig-mcp/adapter/mod.ts",
"action": "flag",
"rule_module": "cicd_rules",
"severity": "critical"
},
{
"reason": "TypeScript file detected -- banned language",
"type": "banned_language_file",
"file": "/home/runner/work/boj-server/boj-server/cartridges/hesiod-mcp/adapter/mod.ts",
"action": "flag",
"rule_module": "cicd_rules",
"severity": "critical"
}
]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
Both
abi-drift(verify) andzig-test(Zig FFI Tests) currently sweep every cartridge undercartridges/*and fail the PR check if any one of them fails. With ~66 cartridges in the abi-drift allowlist and ~73 in zig-test, a PR touching a single cartridge gets gated by unrelated breakage in others — e.g. browser-mcp and orchestrator-lsp-mcp Zig failures, container-mcp/git-mcp/queues-mcp/vordr-mcp ABI drift — that has been sitting onmainfor weeks.This PR constrains both per-cartridge loops on pull_request events to the intersection of:
cartridges/<name>/**in this PR's diff againstorigin/<base_ref>.On
push: mainthe full sweep is preserved, so cross-cutting drift is still caught at trunk. This is purely a PR-time false-positive fix, not a relaxation of the gate.Why now
Surfaced by the investigation in PR #146: that PR touches only
local-coord-mcp, but was blocked by failures in 6+ cartridges it didn't change. The other gating workflows that scan all cartridges have the same pathology; this PR fixes the two that have clean per-cartridge loops.Changes
.github/workflows/abi-drift.yml— new "Restrict to cartridges changed in this PR" step; the verify loop reads the filtered set on PR, full allowlist on push.fetch-depth: 0added so the diff can resolve..github/workflows/zig-test.yml— new "Determine cartridges to test" step; both the FFI tests loop and the shared-library build loop read the in-scope set. Catalogue/readiness steps still run on every invocation — they test cross-cartridge plumbing.Empty changed-set on a PR (which the
paths:filter shouldn't allow, but defensive) emits a::notice::and exits 0 instead of going red on nothing.Out of scope
tests/aspect_tests.sh(the "Aspect — Thread Safety + ABI Contract + SPDX" check) asserts global invariants across the whole tree, so a "changed-files" filter doesn't fit it cleanly. Best handled with a baseline-aware ratchet — separate PR.Test plan
python3 -c "import yaml; yaml.safe_load(...)"both YAML files (clean)zig-test(touches.github/workflows/zig-test.ymlbut nocartridges/**) — expect the "Determine cartridges to test" step to print an empty scope and the per-cartridge steps to no-op via the::notice::pathcartridges/local-coord-mcp/**) should, when rebased onto this once merged, run abi-drift and zig-test against onlylocal-coord-mcpand skip the unrelated failing cartridges🤖 Generated with Claude Code
Generated by Claude Code