Validation Strategy¶
Validation is split into two layers.
Human-runnable gates¶
The validation commands are the source of truth. Hooks may call the same commands, but hooks are optional wrappers, not the main validation surface. Every developer can run the checks from a normal shell:
python tools/validate_docs_coverage.py
python tools/validate_api_cleanliness.py
python tools/validate_public_api_surface.py
python tools/validate_public_api_surface.py --check-contract-permission
python -m pytest -q tests/contracts/tooling
These gates enforce the normal source and public API rules:
keep public imports one layer deep under the current first-layer modules
do not add compatibility aliases, forwarding modules, or dynamic import wrappers to keep old paths alive
keep public exports explicit in literal
__all__listsupdate matching API tests and docs when public exports change
update the public API surface contract only when the user explicitly asks for that change
The tooling also handles explicit workflow or API-change intent:
$add-featureinjects the spec-first feature workflow.Requests such as
update public API surfaceallow one deliberate update tospecs/public_api_surface.json.
Optional local hooks¶
Local hooks are optional convenience wrappers around the commands above. They can be used in the same local automation path as before, but they are not a separate source of rules.
The wrapper entry points are:
python tools/repo_hooks.py user-prompt-hook
python tools/repo_hooks.py stop-hook
At the start of a hook-tracked turn, the wrapper records the current dirty tree. The stop hook then gates only files whose content changed after that turn started. If a file was already dirty or untracked at the start, a later content edit is treated as a modification, not as a new add. This keeps old dirty source files from turning a later docs or example edit into a source validation run.
The stop hook runs these gates:
tools/validate_add_feature.py stop-hookblocks unfinished$add-featurework.For files changed in the current hook-tracked turn,
tools/validate_docs_coverage.pychecks lightweight docs expectations. For example, a new example notebook requiresexamples/README.md, and hook/tooling edits require this validation strategy page or the add-feature workflow README.For
src/files changed in the current hook-tracked turn,tools/validate_api_cleanliness.pyrejects old API paths, compatibility wrappers,sys.modulesaliases, and unclear public imports.When a public
__init__.pyorspecs/public_api_surface.jsonchanges in the current hook-tracked turn,tools/validate_public_api_surface.pychecks that the public export lists still matchspecs/public_api_surface.json.When
specs/public_api_surface.jsonchanges in the current hook-tracked turn,tools/validate_public_api_surface.py --check-contract-permissionblocks the contract update unless the user explicitly asked for one.
Docs, examples, tests, and notebooks do not run the source API gates unless the
same change set also changes src/ or the public API surface contract.
The hook wrapper behavior is covered by
tests/contracts/tooling/test_repo_hooks_router.py. The validators themselves
are covered by the other tests/contracts/tooling/test_*_validator.py files.
The same structural gates run in the CI quality job:
python tools/validate_api_cleanliness.py
python tools/validate_public_api_surface.py
python tools/validate_public_api_surface.py --check-contract-permission
python tools/validate_docs_coverage.py
On pull requests, CI fetches the target branch and passes --base-ref origin/<target-branch> to the diff-based gates. This makes those gates compare
the pull request changes against the branch being merged into. Local no-argument
runs still compare against the current working tree.
Public API contract¶
The public API contract lives in:
specs/public_api_surface.json
It records the names exposed by the first-layer public modules:
fuggers_pyfuggers_py.bondsfuggers_py.creditfuggers_py.curvesfuggers_py.fundingfuggers_py.inflationfuggers_py.portfoliofuggers_py.ratesfuggers_py.vol_surfaces
Update this file only when the user explicitly asks for a public API surface change. Use:
python tools/update_public_api_surface.py
If the public API changed, also update the matching page under docs/api/ and
the matching public API contract tests.
Add-feature workflow¶
$add-feature uses its own spec-first validator and reviewer flow. Start it
with:
python tools/validate_add_feature.py init --slug <feature-slug>
Finish it with:
python tools/validate_add_feature.py validate --mark-passed
Deterministic validation suite¶
tests/integration/validation/ contains scenario fixtures for:
bond pricing and accrued-interest edge cases
callable and floating-rate analytics
portfolio analytics and ETF workflows
engine scheduler and reactive flows
External-reference corpus¶
tests/integration/validation/test_validation_corpus.py consumes tests/fixtures/golden/validation_corpus.json.
The corpus is local and deterministic.
It records the upstream repository, branch, commit, and generation date in fixture metadata.
It is intentionally small and focused on high-value pricing and portfolio workflows.
Accepted divergences are documented inline in the fixture when the Python implementation deliberately optimizes for internal coherence rather than exact path-by-path reproduction.
Tolerances¶
Tight scalar tolerances are used for deterministic bond cases.
Exact or near-exact
Decimaltolerances are used for many portfolio aggregates.Wider explicit tolerances are reserved for model-driven workflows such as callable OAS and floating-rate discount-margin checks.