Skip to content

Foundation hardening verification

Scope: package normalization and quality gates on top of f9e88a6991add6513c66c6e36ba55985eece7306. Recorded 2026-09-20. The dependency audit is failing with documented findings; this change is not a claim of a clean security bill of health.

1. Baseline before changes

The unchanged baseline records 52 passing tests on every Python from 3.8 through 3.14, Ruff, wheel/sdist, outside-checkout installed-wheel CLI, strict MkDocs and a real Python 3.8 Docker smoke test. Branch-aware coverage on Python 3.11 was 55.90%, measured before production edits.

2. Final layout

src/apizr/                 installed application package
  main.py                  existing CLI and conversion entry point
  extensions/              existing Context, engine and pipeline steps
  modules/                 existing analyzer, notebook, FastAPI and Docker modules
tests/                     maintained executable suite
  fixtures/legacy/         all 82 historical fixture files
scripts/                   container, wheel and resolved-dependency audit checks
docs/architecture/         baseline, principles and verification records
LICENSE                    canonical full GPL version 3 text
CONTRIBUTING.md             canonical contribution guide
CODE_OF_CONDUCT.md          existing conduct policy moved to root
SECURITY.md                 supported line and verified private reporting route

3. Exact namespace migration

src/* application files moved to src/apizr/*; internal imports, module commands, Uvicorn examples, test imports and configuration paths now use the new location. The distribution name remains outerspace-apizr, version remains 0.2.0, the license remains GPL-3.0-or-later, and Python remains >=3.8,<3.15. The console script is apizr = "apizr.main:main" and Hatch packages src/apizr. Existing main.py responsibilities are preserved. No src shim or path manipulation was added. The baseline documentation did advertise src; consumers must migrate imports and module invocations as documented in setup.

4. Tests before and after

52 → 55 passed on each of Python 3.8–3.14. Existing tests and golden files remain. Three new cases cover script/notebook deterministic offline generation and the trusted execution boundary (two parameterized cases), plus an unconfigured Context regression. The latter failed with AttributeError before the small fix; it now raises ContextException. Engine control flow, discovery, AST metadata, route generation, dependency inference and Docker algorithms were not redesigned. ArgNode declarations describe existing dynamically assigned fields.

5. Coverage before and after

Comparable Python 3.11 branch-aware coverage: 55.90% → 56.13%. Statement coverage: 57.07% → 57.22%; branch coverage: 50.60% → 51.18%. The final Python 3.14 result is 55.81%; Python 3.9 is 56.07%; Python 3.10–3.13 are 56.13%. Python 3.8 is 69.16% because its older pytest-cov also measures CLI subprocesses; that number is not directly comparable to parent-process results.

Final selected modules: AST analyzer 95.24%, engine 92.86%, Context 81.82%, FastAPI application generator 85.71%. Interactive prompts and old import/service generators remain major gaps. Generated API behavior is exercised with HTTP assertions, but temporary generated code is not included in package coverage.

The 55% floor is deliberately below all measured supported-runtime results. Missing lines are printed in CI. Explicit coverage configuration fixes a real Python 3.8 pytest-cov failure when CLI subprocesses changed directory and mixed statement-only and branch data; the full Python 3.8 rerun passed afterward.

6. Pyright

Standard mode over src/apizr and scripts, targeting Python 3.8: 0 errors, 0 warnings. No blanket ignores, diagnostic suppressions or fake casts. Configuration encoding has a narrow Protocol; version parsing declares its major/minor tuple; existing AST argument attributes are declared. Compatibility backports are installed in the development group for analysis on newer Python. Dynamic metadata and unannotated legacy interfaces remain typing debt.

7. Ruff and pre-commit

ruff check ., ruff format --check . and all pre-commit hooks pass. B, C4, PIE and RUF100 augment E4/E7/E9/F/I. FastAPI File defaults have the specific immutable-call exemption expected by that framework. Golden fixtures are excluded; template bytes and vendored web assets are protected from whitespace rewriting. The large-file check has explicit exceptions for the existing two large images and generated universal lockfile. Black remains a runtime notebook dependency, not a repository formatter.

8. Package build

Wheel and sdist build successfully from a fresh checkout. The wheel contains apizr, its templates/configuration/translations and .dist-info/licenses/LICENSE; it contains no src package. The canonical license text is sourced from GNU; documentation retains the project's copyright and GPL-3.0-or-later notice and links to the root license.

9. Installed wheel

Fresh Python 3.8 and 3.14 virtual environments outside the repository passed import apizr, absence of an installed src namespace, apizr --help, and pricing-notebook generation. The same checks were repeated from the clean checkout on Python 3.14. The smoke script inspects actual wheel contents and the generated output manifest rather than relying on editable imports.

10. Docker

Generated Python 3.8 and 3.14 containers built and ran successfully: health endpoint, POST total = 36, non-root UID. Python 3.8 also passed from the fresh checkout. Other target containers were not run locally during this PR; CI retains all seven targets without repeating lint/build gates in each test job.

11. Security audit

Failed, exit 1, reproduced from the clean checkout. 243 resolved entries were audited. Findings affect 29 package/version entries across 18 packages, with 79 distinct package/version/advisory combinations (the auditor emits 140 records including duplicate advisory IDs). See the complete security baseline for affected versions, advisory IDs, fix versions and verified Python requirements. No ignore list or continue-on-error is used. A separate policy/backport decision is needed to resolve the oldest Python dependency variants without violating this PR's support-range constraint.

12. CodeQL and CI

A Python CodeQL workflow was added with immutable action pins and read-only repository permission. Existing GitHub default setup already scans Python and Actions and publishes alerts. The explicit workflow runs analysis with upload: never and retains SARIF as an artifact for 14 days, avoiding the default-setup upload conflict. It does not disable existing security scanning. If maintainers later switch to advanced setup, enable SARIF upload and grant security-events write permission in the same change. Analysis was not executed locally; GitHub Actions must provide that result. CI separates quality, compatibility, build, containers and security; strict documentation retains its separate workflow. No historical issue was closed and no runtime sandbox or attestation integration was introduced.

13. Files moved or removed

All application files moved under src/apizr. All 82 files from test/ moved unchanged under tests/fixtures/legacy; there is one test hierarchy. Legacy algorithms/templates were retained. Documentation copies of community/license text became links to canonical root documents. Old src/__init__.py is removed from that location; no old namespace package remains in the wheel.

14. Remaining debt

Legacy prompts and generator paths have weak coverage. Context/step results and AST metadata remain dynamically shaped. Standalone CLI subprocess coverage is not unified across pytest-cov versions. Runtime dependency inference depends on the installed environment. Older supported Python versions force vulnerable historical dependencies. CodeQL results and the full hosted container matrix must be assessed in CI. No issue wording was used as grounds for closure.

15. Compatibility risks

The documented src.* import/module paths intentionally change to apizr.*. The apizr command and supported valid generation behavior remain. Malformed version strings with other than two numeric components now fail during explicit major/minor unpacking. Unconfigured Context I/O now reports ContextException instead of leaking AttributeError. No new product features, AI dependencies, plugin implementation, license change or Python range change were made.

16. Commands and change statistics

Baseline commands are in the baseline record. The final verification used a fresh temporary checkout exported from the staged Git tree, with a new .venv. The following commands ran there (all passed except the dependency audit; pre-commit passed after the documented narrow large-file exceptions):

uv sync --locked --python 3.14
uv run ruff check .
uv run ruff format --check .
uv run pyright
uv run pytest
uv run pytest --cov --cov-report=term-missing --cov-report=json:/tmp/apizr-foundation-final/coverage-3.14.json
uv build
uv run --locked --group docs mkdocs build --strict
uv run pre-commit run --all-files
uv run python scripts/smoke_wheel.py dist/outerspace_apizr-0.2.0-py3-none-any.whl
uv run python scripts/smoke_container.py --python-version 3.8
uv run --locked --group security python scripts/audit_dependencies.py --output /tmp/apizr-foundation-final/clean-audit.json

Additional working-checkout verification:

# Each isolated Python 3.8–3.13 environment was first refreshed with:
UV_CACHE_DIR=/tmp/apizr-uv-cache UV_PYTHON_INSTALL_DIR=/tmp/apizr-python UV_PROJECT_ENVIRONMENT=/tmp/apizr-py38 uv sync --locked --python 3.8
# The same command was repeated with py39/3.9 through py313/3.13.
COVERAGE_FILE=/tmp/apizr-foundation-final/coverage38-clean /tmp/apizr-py38/bin/python -m pytest --cov --cov-report=term-missing
# Corresponding py39, py310, py311, py312 and py313 interpreters also ran:
<python> -m pytest --cov --cov-report=term-missing
# Python 3.11 additionally emitted the directly comparable coverage JSON:
/tmp/apizr-py311/bin/python -m pytest --cov --cov-report=term-missing --cov-report=json:/tmp/apizr-foundation-final/coverage-3.11.json
UV_CACHE_DIR=/tmp/apizr-uv-cache uv run --locked python scripts/smoke_wheel.py dist/outerspace_apizr-0.2.0-py3-none-any.whl --python /tmp/apizr-py38/bin/python
UV_CACHE_DIR=/tmp/apizr-uv-cache uv run --locked python scripts/smoke_wheel.py dist/outerspace_apizr-0.2.0-py3-none-any.whl
UV_CACHE_DIR=/tmp/apizr-uv-cache uv run --locked python scripts/smoke_container.py --python-version 3.14
PRE_COMMIT_HOME=/tmp/apizr-pre-commit UV_CACHE_DIR=/tmp/apizr-uv-cache uv run --locked pre-commit run --all-files
git diff --check
git diff --cached --check

/tmp/apizr-foundation-final/clean-commands.json records the exact clean-run argument arrays, working directory, exit codes and log paths. The delivered diff-stat.txt is generated directly from git diff --stat against the baseline, separately from this document so the statistic does not recursively include its own embedded output.