Skip to content

CI delivery: verify the built wheel outside the source checkout and qualify supported OS paths #84

Closed

Description

@andy-zen-dev

Retained delivery debt, revalidated 2026-10-22

This turns the installation/platform-testing proposals from #12 and the retained Hungry Crab ledger in #50 into one bounded implementation task. It is not a claim that the current wheel is broken.

At cumulative head a4761daa9fa87026ea106a3d722e7299b3de3b8b, pyproject.toml declares Python >=3.12, an OS-independent package and a stdlib-only runtime. .github/workflows/ci.yml exercises an Ubuntu/Python 3.12–3.14 editable installation and extensive source-tree tests/replay. The PR #81 author separately reports successful manual wheel installation on Windows. That evidence is useful, but the checked workflow does not continuously prove that a built distribution installs and works without the source checkout on its import path.

Scope

Add a small packaging/installation gate, independent of PyPI publication or production adoption. Build one wheel, install it without runtime dependencies into a clean virtual environment, change to a temporary directory outside the checkout, and exercise installed entry points plus packaged resources. Keep the ordinary source tests; they catch different errors. Document the OS support actually qualified, and add a bounded Windows/macOS smoke matrix only within the maintainer's existing runner budget. Do not start paid runners, introduce runtime dependencies, configure publishing credentials or change repository settings from this task.

Acceptance

  • The workflow builds the wheel from the exact candidate SHA and installs that wheel in a fresh environment with no editable/source-tree import fallback.
  • devostasis --help, an offline fixture build and verification/replay of a valid bundled example succeed from outside the checkout; missing package data or entry points fail the job.
  • Wheel metadata version matches the source version; installed dependencies preserve the empty runtime dependency contract.
  • A deliberately incomplete or wrong-version package is detected by the gate rather than passing because the source tree is importable.
  • Supported OS boundaries are documented and covered by focused path/lock/CLI smoke tests or explicitly marked unqualified; skipped/unavailable runners are not PASS.
  • Timeouts and artifact retention are explicit; no unbounded matrix or automatic publication is introduced.

Related: #24 remains the separate PyPI Trusted Publishing/owner-configuration issue; #78 remains the user-facing first-report acceptance; #12 and #50 are the original proposal sources. Searches across open/closed issues found the broad proposals and #24, not a dedicated recurring isolated-wheel gate. This issue does not close B7, deploy #71, or assert that all OS combinations are already supported.

Activity

  1. andy-zen-dev commented on Oct 23, 2026

    @andy-zen-dev
    Author

    Executable isolated-wheel CI handoff — 2026-10-23

    Revalidated on cumulative PR #81 / #75 head a4761daa9fa87026ea106a3d722e7299b3de3b8b.
    Exact files: .github/workflows/ci.yml blob 42763487e82b2e634cf13b81fe6b65d81935ea1d, pyproject.toml blob d48fa79199f2b43d7e72fddb8de5b1939a489aca.

    The current workflow only installs -e ".[dev]" and runs tests while the source checkout is importable. That is NOT evidence that the built wheel installs and verifies a bundle independently. This is a coverage gap, not a demonstrated wheel defect. Existing #84 acceptance is still correct; no duplicate Issue is needed.

    Prepared bounded implementation

    Add a separate Ubuntu/Python 3.12 wheel-smoke job under jobs:, keeping the existing test job unchanged:

      wheel-smoke:
        name: Installed wheel (Ubuntu, Python 3.12)
        runs-on: ubuntu-latest
        timeout-minutes: 10
        steps:
          - uses: actions/checkout@v4
            with:
              ref: ${{ github.event.pull_request.head.sha || github.sha }}
          - uses: actions/setup-python@v5
            with:
              python-version: "3.12"
          - name: Build exact candidate wheel
            shell: bash
            run: |
              set -euo pipefail
              python -m pip install --quiet build
              python -m build --wheel --outdir "$RUNNER_TEMP/wheel-dist"
              test "$(find "$RUNNER_TEMP/wheel-dist" -maxdepth 1 -name '*.whl' | wc -l)" -eq 1
          - name: Install and smoke-test outside checkout
            shell: bash
            run: |
              set -euo pipefail
              expected=$(python -c 'import pathlib, tomllib; print(tomllib.loads(pathlib.Path("pyproject.toml").read_text())["project"]["version"])')
              export EXPECTED_DEVOSTASIS_VERSION="$expected"
              venv="$RUNNER_TEMP/wheel-venv"
              python -m venv "$venv"
              "$venv/bin/python" -m pip install --no-index --no-deps "$RUNNER_TEMP"/wheel-dist/*.whl
              mkdir -p "$RUNNER_TEMP/outside-checkout"
              cd "$RUNNER_TEMP/outside-checkout"
              unset PYTHONPATH
              "$venv/bin/python" -I - <<'PY'
              import importlib.metadata as metadata
              import os
              from pathlib import Path
              import devostasis
              dist = metadata.distribution("devostasis")
              assert dist.version == os.environ["EXPECTED_DEVOSTASIS_VERSION"], dist.version
              requires = dist.metadata.get_all("Requires-Dist") or []
              assert all("; extra ==" in requirement for requirement in requires), requires
              assert any(ep.group == "console_scripts" and ep.name == "devostasis"
                         and ep.value == "devostasis.cli:main" for ep in dist.entry_points)
              venv_root = (Path(os.environ["RUNNER_TEMP"]) / "wheel-venv").resolve()
              assert Path(devostasis.__file__).resolve().is_relative_to(venv_root), devostasis.__file__
              PY
              "$venv/bin/devostasis" --help >/dev/null
              "$venv/bin/devostasis" verify --bundle "$GITHUB_WORKSPACE/examples/sample-bundle"
              "$venv/bin/devostasis" build \
                --observations "$GITHUB_WORKSPACE/examples/observations.json" \
                --store "$RUNNER_TEMP/outside-checkout/store" \
                --planning milestones --debt-label type:refactor \
                --debt-mapping-version example-1
              "$venv/bin/devostasis" verify \
                --bundle "$RUNNER_TEMP/outside-checkout/store/projects/github.com/acme/widget/latest"
              if EXPECTED_DEVOSTASIS_VERSION=not-a-release "$venv/bin/python" -I -c \
                'import importlib.metadata as m, os; assert m.version("devostasis") == os.environ["EXPECTED_DEVOSTASIS_VERSION"]' 2>/dev/null; then
                echo "Version mismatch negative control unexpectedly succeeded" >&2
                exit 1
              fi

    Isolation: fresh venv; wheel installed with --no-index --no-deps; cd outside checkout; PYTHONPATH unset; python -I confirms imports resolve into venv, not the source tree. The console-script smoke, stored sample verification, and built fixture verification exercise actual installed entry points. Metadata must match pyproject.toml; optional dev-extra requirements may be recorded, but unguarded runtime dependencies are not accepted. The intentionally false version is a test of the fail-closed version assertion.

    Local verification performed: git apply --check against the matching CI context PASS; git apply on that context PASS; PyYAML parse PASS; bash -n for both run blocks PASS. NOT_RUN: actual wheel build/install, real Devostasis smoke, Windows/macOS matrix and hosted CI (the exact PR #81 SHA currently has workflow conclusions action_required, not PASS).

    Release discipline: feature change should target current release/0.6.0, receive later independent review, and not land directly on master. This job qualifies only Ubuntu/Python 3.12. Other OS paths remain UNQUALIFIED until actual hosted runs.

    The maintainer connected account currently has pull=true / push=false, so the checked candidate is a ready-to-apply handoff, not an opened PR, not merged code and not a verified wheel release.

  2. andy-zen-dev commented on Oct 24, 2026

    @andy-zen-dev
    Author

    Bounded implementation handoff for #84 — an actual wheel consumer gate (2026-10-24)

    Source checked: release/0.6.0; pyproject.toml blob 956baa1de977ebc23e7e27f00f12aeb4a9712e6f, src/devostasis/__init__.py blob 9a0dad92dbfea263a7e4676906c8cb6086775f5c, .github/workflows/ci.yml blob c94bd7ff32abd4cd7f8f81cdc633c35e13f99da8. Current CI uses pip install -e ".[dev]" in Ubuntu 3.12–3.14, so source-tree passing tests do not prove that a noneditable built wheel can run independently. The package declares version 0.6.0 and no runtime dependencies.

    Prepared executable unit: scripts/wheel_smoke.py (stdlib-only; ~140 lines) plus this additive CI job (no change to the existing test matrix):

      wheel-consumer:
        name: Installed wheel smoke (Python 3.12 / Ubuntu)
        runs-on: ubuntu-latest
        timeout-minutes: 10
        permissions:
          contents: read
        steps:
          - uses: actions/checkout@v4
          - uses: actions/setup-python@v5
            with:
              python-version: "3.12"
          - name: Build candidate wheel
            run: |
              python -m pip install --quiet "build>=1.2"
              python -m build --wheel --outdir "$RUNNER_TEMP/wheel"
          - name: Install and smoke wheel outside checkout
            run: python scripts/wheel_smoke.py --repo "$GITHUB_WORKSPACE" --wheel-dir "$RUNNER_TEMP/wheel"

    The prepared script is a concrete implementation of that final command. Before installation it requires exactly one wheel; checks wheel metadata name and exact source version, entry point devostasis = devostasis.cli:main, actual devostasis/__init__.py and cli.py members, RECORD/WHEEL metadata, and no non-extra Requires-Dist. It then creates an independent venv, installs only the wheel with --no-index --no-deps, strips PYTHONPATH/PYTHONHOME, changes CWD to a temporary directory outside the checkout, verifies imports originate under the fresh venv with python -I, and exercises installed devostasis --help, sample bundle verification, work verify/replay, code verify/verify-packet, and an offline observations build using copied external fixtures. Every subprocess has a timeout and any failure terminates the gate. Build tooling may access package indexes; the installed runtime smoke does not.

    Local checks actually executed (Python 3.13.5; NOT repository integration): script py_compile PASS; YAML parsed PASS; four synthetic wheel preflight cases 4/4 PASS (valid control accepted; missing CLI, wrong version, and non-extra runtime dependency each rejected). Synthetic wheels were not installed. No actual Devostasis wheel was built/installed here because the complete repository checkout was unavailable; full pytest, example replay and CI remain NOT_RUN / NOT_PASS.

    Prepared artifact digests for exact handoff:

    • scripts/wheel_smoke.py SHA-256 f629431aaf346fe089c70653b4bc5b6f374da3e0297a6ae172974397b6c46343
    • additive CI YAML SHA-256 e1321fbae02874efd0d22263223bff8363a8011e9b8ca3ab358ead2f4b766ee1

    Acceptance next: add the script and job on a focused feature branch targeting release/0.6.0; run the wheel job on the exact head; verify a deliberately broken built wheel fails on the hosted runner. This only qualifies Ubuntu/Python 3.12 wheel consumption, not Windows/macOS or PyPI publishing (#24). As of this run, connected andy-zen-dev has pull=true,push=false: this comment is an implementation handoff, not a pushed branch/PR, passing wheel integration, merge or release.

    2026-10-24 correction — the prepared wheel preflight can falsely accept runtime dependencies

    Independent check of the prior handoff, not a newly pushed fix. The scripts/wheel_smoke.py prepared above currently admits every Requires-Dist containing the substring ; extra ==. That is insufficient to prove zero runtime dependencies.

    Concrete counterexample in a wheel METADATA field:

    Requires-Dist: somepkg>=1; extra == "dev" or python_version < "99"
    

    The prior predicate re.search(r";\\s*extra\\s*==", requirement) accepts it, yet PEP 508 evaluates this dependency as active with no extra selected on supported Python versions. Installing the wheel with --no-deps could then hide the accidental dependency if the smoke only exercises unrelated paths. This is a packaging-gate false PASS, not evidence that current Devostasis metadata is wrong: its pyproject.toml still declares dependencies = [] and dev = ["pytest>=8"].

    Minimal conservative stdlib-only repair (replace the old search):

    def requires_only_optional_extra(requirement: str) -> bool:
        distribution, separator, marker = requirement.partition(";")
        if not separator or not distribution.strip():
            return False
        return re.fullmatch(
            r"\s*extra\s*==\s*(?:\"[A-Za-z0-9_.-]+\"|'[A-Za-z0-9_.-]+')\s*",
            marker,
        ) is not None
    
    for requirement in metadata.get_all("Requires-Dist", []):
        require(requires_only_optional_extra(requirement),
                f"dependency is not provably extra-only: {requirement}")

    This intentionally rejects complex and/or markers even when some would be truly optional: unproven is not PASS. It still accepts the expected pytest>=8; extra == "dev" emitted for Devostasis's development extra. A future complex marker should receive an explicit PEP 508 evaluator, not a substring heuristic.

    Verification performed locally: 9/9 synthetic wheel preflight tests PASS (no dependency, both quote styles for the optional dev extra, bare runtime dependency, non-extra Python marker, OR bypass, conservative AND, extra inequality, and source/wheel version mismatch). py_compile PASS. The patch against the previous prepared script has SHA-256 9874c5d9828fb6930698673faa5d4eeb5cbac0d37498189d47f775563950f61f. NOT_RUN: real Devostasis wheel build/install, full checkout pytest, historical replay, actual CI on a fixing head. The prior standalone script handoff must be treated as superseded by this correction; #84 remains open.

  3. drevendev commented on Oct 24, 2026

    @drevendev
    Owner

    Taking the bounded implementation of #84 on branch ci/84-isolated-wheel-smoke, based on upstream release/0.6.0 (22a2894057d9b1bc003efe4ef932ed4de601e26b). Scope: a stdlib-only wheel preflight/installed-consumer smoke script, focused negative controls, a separate bounded Ubuntu/Python 3.12 CI job, and precise qualification documentation. I will run an actual built wheel outside the source checkout on native Windows, independently review the exact change, verify the exact PR head in existing CI, then merge into the release branch if checks pass. Existing test jobs, runtime dependencies and release/forge settings remain unchanged. The prior handoff's broad dependency-marker predicate will not be reused. This does not accept #81 or publish 0.6.0.

  4. added a commit that references this issue on Oct 24, 2026
  5. drevendev commented on Oct 24, 2026

    @drevendev
    Owner

    Completed and merged as PR #91 into release/0.6.0; verified merge commit 5998723411bd2721971a7385ca2d8c8af8df055f retains reviewed head 0f7c65a230b0411571ef36decb4343f991cbb8f8 with an identical tree.

    The isolated-wheel gate, 12 focused regressions, bounded CI job and qualification documentation are delivered. Actual native Windows/Python 3.14.7 wheel consumption passed; full offline pytest: 2385 passed. A separate read-only same-host agent reviewed the exact diff and independently repeated all 12 focused tests and the full wheel gate from a git archive export, with no actionable findings. Exact-head CI run 40102292043 passed all four jobs: Ubuntu/Python 3.12 installed-wheel smoke and Python 3.12/3.13/3.14 source tests. All four damaged actual-wheel controls were refused, including the extra-marker OR bypass.

    The selected local release checkout was fast-forwarded and verified clean. This task's remote/local feature branch was removed only after ancestor and expected-SHA checks. No other feature branches were cleaned up.

    This closes the bounded wheel-delivery gate. macOS/other wheel-consumer combinations and privileged path behavior remain explicitly unqualified; #24 publishing and the pending release-chain/first-adopter gates remain separate. No version was published.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions