pagination-claim-audit
Offline audit of documented pagination claims against Python source.
Version 0.1.0. Requires Python 3.9 or newer. Runtime uses only the standard library. Analysis runs offline and never executes or imports target code.
Usage
python3 -m pip install .
pagination-claim-audit /path/to/project
python3 -m pagination_claim_audit /path/to/project --json
pagination-claim-audit . --verbose --ignore 'vendor/*' --ignore 'generated/*'
pagination-claim-audit . --fail-on HIGH
pagination-claim-audit --version
PYTHONPATH=src python3 -m unittest discover -s tests -v
python3 -m build
The path defaults to the current directory. --ignore is repeatable and
matches case-sensitive relative path globs. --json emits an object with
version, findings, and verified_claims; each finding carries rule,
severity, claims, and evidence. --verbose shows claim and evidence
locations in text mode. Usage, unreadable input, and syntax errors exit 1.
A clean audit exits 0; findings at the selected threshold exit 2. The default
threshold is MEDIUM. HIGH allows MEDIUM findings to remain visible with exit 0.
Claims
Only root README.md and docs/**/*.md supply claims. Fenced code is excluded; inline code spans count as prose. Exact phrases are matched case-insensitively with word boundaries. There are two independent claim families. The complete phrase inventory is shown here, within a fence to keep self-audits clean:
PAGINATED:
paginated
paginated results
paginated output
supports pagination
with pagination
page through results
fetches results page by page
fetches page by page
results are paginated
output is paginated
pages through results
SINGLE-SHOT:
returns all results at once
fetches all results at once
all results in one request
in a single request
no pagination
without pagination
unpaginated
single-page results
returns everything at once
Explicit negative example interpreted as SINGLE-SHOT:
results are not paginated
Negation is asymmetric: a sentence containing no, not, never, without,
doesn't, don't, or isn't suppresses the affirmative paging family. Negative
phrases in the second family still count as promises of a single response.
Other second-family phrases are suppressed in negated sentences. The explicit
negative example above also belongs to the second family. A bare page noun
and the noun phrase pagination support are not claims. The adjective in the
first line of the inventory is sufficient by itself. Spelling and hyphenation
must match the inventory; arbitrary wording variants are not inferred.
Rules
One finding is emitted per contradicted family; repeated prose is retained within its claims list. A tree with both families is evaluated independently.
| Rule | Severity | Condition |
|---|---|---|
| documented-paginated-claim-false | HIGH | Affirmative paging claim without production or test evidence |
| documented-paginated-claim-false-test-only | MEDIUM | Affirmative paging claim supported only by test evidence |
| documented-single-shot-claim-false | HIGH | Single-response claim with production paging evidence |
| documented-single-shot-claim-false-test-only | MEDIUM | Single-response claim with only test paging evidence |
With no production Python source, each present family gets its HIGH rule and
no-source evidence. Affirmative paging claims with production evidence are
verified. Single-response claims without any evidence are verified. With no
claims, the audit passes regardless of evidence.
Named evidence
| Kind | Static signal |
|---|---|
| pagination-parameter | Function or async function with a listed parameter |
| pagination-keyword | Call using a listed keyword argument |
| next-page-call | Attribute call to next_page, fetch_next_page, get_next_page |
| next-page-access | Attribute or literal subscript access to next_page, next_page_token, next |
| paging-loop | While body contains one of those signals; extra item only on a distinct line |
The parameter/keyword set is page, page_number, page_size, per_page,
limit, offset, cursor, next_page_token, continuation_token,
start_after, and page_token. Each definition or call site contributes one
item per kind, deduplicated by file, line, and kind. All relevant evidence
appears in a contradiction finding. A loop condition can supply access
evidence, but an additional loop item requires a signal in its body.
Production excludes tests/ and fixtures/ directories, test_*.py and *_test.py; these contribute only test evidence. docs/ and examples/ source is excluded. Symlinked files and directories are skipped. Environment files are never opened. Only Markdown claim sources and eligible .py files are read. The scanner also skips .git, virtual environments, build artifacts and caches.
Differentiation
| Neighbour | Its question | This tool's question |
|---|---|---|
| streaming-claim-audit | Local read chunking | Result paging promises |
| retry-claim-audit | Attempt counts | Result splitting promises |
| api-claim-audit | Symbols and signatures | Paging behaviour |
| schema-claim-audit | Field names | Page structure promises |
| bandit / ruff | Code issues | Documentation versus source |
| requests / httpx pagination helpers | Paging primitives | Documentation versus source |
Honest limitations
This is static evidence, not a proof that a fetch reaches a remote service.
Dead code counts. A limit keyword on a non-fetch call still counts, an
intentional over-approximation. A local variable or ordinary attribute named
page alone does not count; a function parameter by that name does. Dict keys
such as page or limit alone do not establish a fetch. Iterating
for page in pages alone does not establish fetch-time paging either.
Third-party helpers such as Django Paginator, SQLAlchemy paginate, and
requests wrappers are out of scope unless they expose the recognized names.
Response-like next-field access is recognized syntactically without type
inference. Dynamic keywords, aliases, computed keys and runtime control flow
are not resolved. Exact-phrase matching misses paraphrases and can mistake
quoted prose for a promise; use a fenced block for illustrative phrases.
There is no reachability analysis or network access. Source must parse and
text files must be UTF-8; analysis errors are reported as usage errors.
Fixtures and unittest tests ship in the source distribution via MANIFEST.in. The wheel exposes both the console command and module entry point. MIT licensed; see LICENSE.
Metadata
Release files for pagination-claim-audit 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| pagination_claim_audit-0.1.0.tar.gz | 14.6 kB | Without provenance | Details for pagination_claim_audit-0.1.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| pagination_claim_audit-0.1.0-py3-none-any.whl | Python 3 | none | any | Details for pagination_claim_audit-0.1.0-py3-none-any.whl |
Total release size: 24.0 kB
Release files / pagination_claim_audit-0.1.0.tar.gz
| Download URL | pagination_claim_audit-0.1.0.tar.gz |
|---|---|
| Size | 14.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
13d4ca5f91ea8d9cea1561dfd4b13ecaf92d05fd778700d52307559d902bb0f9
|
|
BLAKE2b-256 checksum How to use checksums |
67a9cd4d343d95afdcb1baa318ba24e7fbaf7cb4aa51478a4544d211044aaf81
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.3
|
Release files / pagination_claim_audit-0.1.0-py3-none-any.whl
| Download URL | pagination_claim_audit-0.1.0-py3-none-any.whl |
|---|---|
| Size | 9.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
2f95cd1c475613405fec31be1eb0adad7d288606302aa9ee4b8fbac6d894665d
|
|
BLAKE2b-256 checksum How to use checksums |
114a275bdc728c964f83773ec59105aa1450f28e79a54294d4f1193a5c510668
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.3
|
Security for pagination-claim-audit 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.