agentleFS
ivklgnivklgn/ai-kit/skills/compatibility-audit/SKILL.md

compatibility-audit

Skill12 starsChanged 2 months agoMITView on GitHub

Audit whether a change is compatible with everything around it, across four boundaries — the contract it exposes to consumers, how cleanly it fits the conventions and abstractions of the place it lives, whether the change was carried through everywhere it had to be, and whether it survives its runtime environment. Scope is either the current git changes (working tree, staged, or branch vs merge base) or an explicit path — a module, package, class, function, file, schema, or config. Language-, domain- and artifact-agnostic — works the same for a new API endpoint, a Go package refactor, a single class, a frontend component, a database migration, or a devops/CI configuration. Emits a per-axis verdict (OK/RISK/FAIL) with evidence-backed findings and a compatible / conditionally compatible / incompatible ruling plus a migration path. Use when asked whether a change will break anyone, whether a piece of code still fits its surroundings, before merging a refactor, when extracting or upgrading a shared package, when adding or altering an API, or to review how cleanly the current edits integrate.

1 other project uses a version of this.

Adopted by

Most recently taken up by

The file

We split this skill into the rules it gives an agent

8 rules. About 0 are common, 7 are distinctive, and 1 is very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈7

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 1

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Run the bundled scope resolver — it handles baseline detection, all change states, and path scoping (paths are relative to this skill's …

    line 28
  2. Distinctive:

    Before judging anything, establish three facts:

    line 48
  3. Distinctive:

    Do not stop at static analysis.

    line 91
  4. Very specific:

    Use the matching contract-diff tool when its config is present (oasdiff, buf breaking, graphql-inspector, cargo semver-checks, Pact) and …

    line 94
  5. Distinctive:

    Never report COMPATIBLE while a gate is failing or unrun for a blocker-suspect change — downgrade honestly and put it in Gaps.

    line 145
  6. Distinctive:

    Every Integration finding cites the local precedent it contradicts.

    line 146
  7. Distinctive:

    Do not fix the code. Report, then offer to implement the "Required before merge" list as a separate step.

    line 148
  8. Distinctive:

    Keep the axes separate in the report.

    line 150

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Compatibility Audit

Answer one question: is this change safe and clean with respect to everything it touches?

The audited unit can be anything with a boundary — a package, a module, a class, a single function, an endpoint, a schema, a config file. The word "surface" below means whatever that unit exposes.

Compatibility here is not only "does it break the build". Any change sits inside four boundaries, and it is compatible only when it agrees with all four:

AxisBoundaryThe question
ContractWhat it exposes outwardDoes anything that depends on it still work?
IntegrationThe context it lives inDoes it match the conventions and reuse the abstractions of this place?
CompletenessThe closure of the changeWas the change carried through everywhere it had to be?
EnvironmentWhat it executes onDoes it survive its runtime, platform, and rollout?

This works across languages and domains because the axes are fixed while the reference standard is discovered per repository. Never judge against a generic best practice — judge against what this repo already does, and cite it.

This skill assesses; it does not fix. Evidence over intuition: every finding cites a file and line, a diff hunk, or a command result.

Step 0: Resolve the Scope

Run the bundled scope resolver — it handles baseline detection, all change states, and path scoping (paths are relative to this skill's directory):

sh scripts/resolve_scope.sh                      # current git changes vs merge base
sh scripts/resolve_scope.sh path/to/target       # a package, module, file, schema, or config dir
sh scripts/resolve_scope.sh --base v1.4.0 pkg/   # explicit baseline

It prints BASE, MODE, COUNT, the changed files, the manifests that govern them, and the touched directories. Parse that output; do not re-derive it.

The three modes mean different things:

  • git-changes / path-scoped-changes — baseline is BASE, candidate is the working tree. Diff with git diff <BASE> -- <paths>.
  • path-snapshot — no pending changes in that path. Audit the code as it stands against its current consumers ("is this thing in good standing?"). Contract findings become "risk in the existing surface" rather than "regression".
  • COUNT 0 — nothing to audit. Ask the user what to audit; do not guess.

For a change that is proposed but not yet written, treat the current tree as baseline and audit the proposal on paper against the same four axes.

Step 1: Map the Scope onto Surfaces and Consumers

Before judging anything, establish three facts:

  1. What is the public surface of the changed thing — what crosses its boundary.
  2. Who consumes it — every caller, importer, subclass, deployment, or reader of its data.
  3. What the local norm is — how the neighbouring code solves the same problems.

The mapping from artifact kind to surface and consumers is in references/surface-map.md — read it now, and read only the rows matching the manifests and file types in scope (code module, HTTP/RPC/GraphQL API, database schema, event payload, UI component, CLI, config/IaC/CI, published package). It also lists where consumers hide in each case.

Anything not reachable from outside the boundary is internal: note it as exempt from Contract, but it still counts for Integration.

Establish the local norm by reading siblings, not by recalling conventions: the other files in the same directory, the nearest equivalent module, the repo's lint/format config, and any project rules (CLAUDE.md, .archcore/, CONTRIBUTING, ADRs). A convention with no local precedent is not a finding.

Step 2: Contract — Will Consumers Break

Walk the diff of the public surface and classify each change into exactly one primary category:

CategoryMeaningTypical evidence
additiveNew capability; existing consumers unaffectednew export, new optional param/field, widened input type
source-breakingConsumers fail to compile/typecheckremoved/renamed export, narrowed param type, new required param, changed generic signature
runtime-breakingCompiles but fails at runtimechanged thrown/returned error shape, sync→async, removed dynamic property, changed argument order in untyped code
behavioralSame signature, different observable behaviorchanged defaults, ordering, rounding, timezone handling, validation strictness, side-effect timing
data-breakingPersisted or transmitted data incompatibleschema migration without backfill, changed serialization field names/types, cache key format change
dependency-breakingConsumers' dependency resolution breakspeer-dependency major bump, dropped runtime/engine version, new transitive conflict, license change

Behavioral changes are what diffs hide best — read the changed bodies of every public symbol, not just the signatures.

Step 3: Integration — Does It Fit Where It Lives

This is the "quality and cleanliness" axis: the change may break nobody and still be wrong for this place. Probe convention conformance, abstraction reuse, dependency direction, duplication, surface economy, and coupling.

The probes, and the rule that every finding must cite a local precedent, are in references/integration-fit.md — read it before judging this axis or Completeness.

Step 4: Completeness — Was the Change Carried Through

A half-applied change is a compatibility defect even when every piece compiles. Check that all call sites moved, that tests/docs/config/CI/types followed, that no dead remnant of the old shape survives, and that parallel implementations were not left behind. Probes are in the same reference file.

Step 5: Environment — Does It Survive Its Runtime

Check the change against what it actually runs on: language/toolchain version floors, target platforms and browsers, engine and container constraints, required env vars and secrets, feature flags, and — for anything deployed — whether old and new instances can coexist during a rolling release (old readers vs new writers, and the reverse). Detection commands per ecosystem are in references/verification.md.

Step 6: Verify With Real Gates

Do not stop at static analysis. Run what exists:

  • Build/typecheck and test the packages that consume the changed surface, scoped to the affected ones.
  • Use the matching contract-diff tool when its config is present (oasdiff, buf breaking, graphql-inspector, cargo semver-checks, Pact) and normalize its output into the classification table above.
  • Record each command and its result. A passing gate is evidence; an unrun gate is a gap that must appear in the report.

Commands per ecosystem, and what to do when no gate exists, are in references/verification.md.

Step 7: Report

Assign a severity to every finding: blocker (a known consumer breaks, or the change is demonstrably incomplete), warn (could break consumers you cannot see — published API, dynamic access, serialized data in the wild — or violates a local precedent), info (additive or internal).

Then roll up: an axis is FAIL with any unresolved blocker, RISK with any warn, otherwise OK.

## Compatibility Audit — <scope> (<BASE>..<candidate>, mode: <MODE>)

**Verdict: COMPATIBLE | CONDITIONALLY COMPATIBLE | INCOMPATIBLE**

| Axis | Result | One-line reason |
|---|---|---|
| Contract | OK | no public surface removed or narrowed |
| Integration | RISK | own retry loop instead of the shared one |
| Completeness | FAIL | 2 of 5 call sites still on the old signature |
| Environment | OK | toolchain floor unchanged |

### Findings
| # | Axis | Severity | Category | Finding | Evidence | Affected |
|---|---|---|---|---|---|---|
| 1 | Completeness | blocker | — | `runJob` still called with the removed 2-arg form | cmd/cli/run.go:41 | cmd/cli |
| 2 | Integration | warn | — | hand-rolled retry; `pkg/retry.Do` is the established one (pkg/queue/worker.go:63) | internal/api/client.go:88 | — |

### Verification
| Consumer / Gate | Command | Result |
|---|---|---|
| cmd/cli | `go build ./cmd/...` | FAIL — 2 errors |

### Gaps
- <surfaces or consumers that could not be exercised, and why>

### Required before merge
1. <ordered, concrete steps>

Verdict rules:

  • INCOMPATIBLE — at least one unresolved Contract blocker: a known consumer breaks.
  • CONDITIONALLY COMPATIBLE — no Contract blocker, but any axis is FAIL or RISK. List every condition under "Required before merge"; a conditional verdict with an empty list is invalid.
  • COMPATIBLE — all four axes OK, with the gates in Step 6 actually run.

For every blocker, propose the cheapest safe path, in this order: preserve compatibility (overload, optional param, deprecated alias, adapter shim, dual-write migration) → staged deprecation with warnings → coordinated breaking change with a written migration guide and, for a published package, a major version bump.

Rules

  • Never report COMPATIBLE while a gate is failing or unrun for a blocker-suspect change — downgrade honestly and put it in Gaps.
  • Every Integration finding cites the local precedent it contradicts. Without a precedent it is a preference, and preferences are not findings.
  • Behavioral compatibility claims require reading the implementation, not just the signature diff.
  • Do not fix the code. Report, then offer to implement the "Required before merge" list as a separate step.
  • An undefined public surface (no export manifest, everything imported ad hoc) is itself a Contract finding — report it rather than inventing a boundary.
  • Keep the axes separate in the report. "It breaks callers" and "it is ugly here" have different costs and different owners.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.