API and schema compatibility rules¶
Rule-pack rigor-foundry/1.16.0 adds the bounded api-compatibility category
(prefix AA). Its findings are anchored needs-evidence candidates, not a
claim that a public change is breaking or that semantic versioning was
violated.
Rule¶
| Rule | Signal | Confidence |
|---|---|---|
AA001-unbound-api-manifest |
a module-level literal Python __all__ surface is absent from, differs from, or cannot be resolved against the tracked root manifest |
high |
AA001 compares Python modules below the configured production source roots
with the fixed repository-root path rigor-public-api.json. It recognises one
direct module-level assignment or annotated assignment whose value is a list
or tuple of unique Python identifiers. The names are normalised into sorted
order before comparison. Function-local and class-local declarations are not
public module surfaces.
Mutation, repeated assignment, computed values, unpacking, non-string members, duplicates, and invalid identifiers make a declaration dynamic. Dynamic surfaces remain review candidates because a static scanner cannot bind their runtime value. Syntax-invalid Python remains outside AA001; the applicable parser or test-authenticity rule owns that condition.
The mutation signal is deliberately syntactic and bounded. It recognises
direct name, attribute, and subscript writes; mutable-sequence operations;
and expressions evaluated in decorators, defaults, annotations, class bases,
and class keywords. Deferred function/lambda bodies, class-local declarations,
lazy PEP 695 aliases, and indirect mutation through reflective helpers or
aliases are outside this signal. from __future__ import annotations is
honoured so deferred annotation text does not become a false candidate.
Manifest schema¶
The tracked JSON document uses schema 1.0 and accepts no additional fields:
{
"schema_version": "1.0",
"surfaces": [
{
"exports": ["AuditReport", "scan_repository"],
"path": "src/example/__init__.py"
}
]
}
Surface paths must be sorted, unique, canonical repository-relative POSIX
paths ending in .py. Export arrays must be sorted and unique, and every
member must be a Python identifier. A malformed or non-text manifest, a
recorded row without a corresponding declaration, and a declaration without a
recorded row each fail closed as separate candidate states.
A repository with neither a tracked manifest nor a qualifying declaration is outside the rule's applicability and receives no AA001 candidate. A matching manifest is also quiet. AA001 never interprets arbitrary source edits as API changes.
Evidence and review¶
Candidate evidence records state, counts, file identity, and canonical SHA-256 surface identities. It does not copy export names or source excerpts. The candidate anchor binds either the exact declaration blob and line span or the exact manifest/repository state.
Reviewers should identify downstream compatibility requirements and decide
whether the observed surface is intentional. Update rigor-public-api.json
only after that review; a matching edit closes manifest drift but does not by
itself establish backward compatibility. Runtime attributes, signatures,
serialized schemas, native ABIs, re-export behavior without __all__, and
non-Python languages require their own evidence controls.
AA001 contributes the portable control for
api-abi-schema-compatibility. It enters maturity probation and cannot drive
enforcement until cross-repository adjudication and reviewer-effort evidence
satisfy the configured maturity policy.