Skip to content

Harden packaging: audit out-of-package runtime data + clean-install smoke test - #82

Merged
Permea-lab-admin merged 2 commits into
mainfrom
feat/packaging-hardening
Jul 25, 2026
Merged

Harden packaging: audit out-of-package runtime data + clean-install smoke test#82
Permea-lab-admin merged 2 commits into
mainfrom
feat/packaging-hardening

Conversation

@Permea-lab-admin

Copy link
Copy Markdown
Collaborator

Phase A verdict

Does anything break in a clean install? NO. No user-reachable CLI command reads data that lives outside the shipped package trees (permea_core, permea_explain, permea_ui).

Audited every entry point — permea, permea bench, permea bench diagnose, and the separate permea-drylab script:

command reads out-of-package data? which paths
permea / permea bench / --help no argparse only
permea bench diagnose DATASET CLUSTERS no only the user-supplied dataset CSV + clusters TSV; downstream run()diagnose()contracts/warnings.py are pure Python
permea-drylab no UI assets are in-package (permea_ui/static/, already shipped via package-data); temp dirs + user uploads only

The many repo-root-relative path constants found by grep (ROOT = Path(__file__).resolve().parents[3], Path("docs/examples/generated"), Path("benchmarks/*.yaml"), Path("acquisition_manifests"), …) all live in artifact-generation modules driven by scripts/, none of which is reachable from the permea CLI. A clean-venv command sweep from outside the repo produced no FileNotFoundError / ModuleNotFoundError / missing-resource error.

What changed

  • pyproject.toml: added a dev optional-dependency group (build, twine, pytest) so a canonical sdist+wheel can be produced and CI can run the suite. No upload to PyPI in this task.
  • pyproject.toml: registered slow and packaging pytest markers.
  • tests/test_packaging_smoke.py: one clean-install smoke test (marked slow+packaging) — builds a real wheel, installs it into a throwaway venv, and drives permea bench diagnose from outside the repo on files produced by permea_ui.fixtures.write_example, asserting exit 0 and a fired warning code. It gates on a real python -m build capability probe (not import build), so it skips cleanly without the dev extra and runs in CI where .[dev] is installed. This exists because the existing suite runs against an editable install and structurally cannot catch a packaging regression.
  • Hygiene: removed stray untracked src/permea_core/.DS_Store (.DS_Store already in .gitignore); deleted the finished untracked doc docs/pr/PR-permea-explain-and-packaging.md.

Deliberately left alone

  • No files moved, no package-data rule added — Phase A found no breakage, so moving data would ship files nothing needs. (Explicitly out of scope: schemas/, examples/, benchmarks/, sources/, etc. are used only by scripts/, never by the wheel's CLI.)
  • No runtime logic changed. permea_explain/guardrails.py verified unmodified (sha256 03468738…b2b2732).

Test count

  • Before: 562 passed.
  • After: 562 passed, 1 skipped locally (93.2s) — the new packaging test skips without pypa-build; it was exercised for real in a venv with the dev extra (1 passed in ~89s) and will run in CI.

🤖 Generated with Claude Code

Permea-lab-admin and others added 2 commits July 24, 2026 18:42
…l smoke test

Audit (no runtime change): traced every user-reachable CLI entry point
(permea, permea bench, permea bench diagnose, and the separate permea-drylab
script) for reads of data living outside the shipped package trees
(permea_core, permea_explain, permea_ui). Verdict: none. `permea bench
diagnose` reads only user-supplied dataset/clusters; its downstream
run()/diagnose()/warnings registry are pure Python. The many repo-root-relative
path constants (ROOT = parents[3], Path("docs/examples/generated"),
Path("benchmarks/*.yaml"), ...) all live in artifact-generation modules driven
by scripts/, not exposed through the CLI. A clean-venv sweep from outside the
repo confirmed no FileNotFoundError / ModuleNotFoundError / missing-resource on
any command. Because nothing broke, no files were moved and no package-data rule
was added -- moving unused data would ship files nothing needs.

Changes:
- pyproject.toml: add a `dev` optional-dependency group (build, twine, pytest)
  so a canonical sdist+wheel can be produced and CI can run the suite. No upload.
- pyproject.toml: register `slow` and `packaging` pytest markers.
- tests/test_packaging_smoke.py: one clean-install smoke test (marked
  slow+packaging) that builds a real wheel, installs it into a throwaway venv,
  and drives `permea bench diagnose` from outside the repo on files produced by
  permea_ui.fixtures.write_example, asserting exit 0 and a fired warning code.
  The existing 562 tests run against an editable install and structurally cannot
  catch a packaging regression; this closes that gap. It gates on a real
  `python -m build` capability probe (not `import build`) so it skips cleanly
  when the dev extra is absent and runs in CI where `.[dev]` is installed.

Hygiene:
- Remove stray src/permea_core/.DS_Store (untracked; .DS_Store already ignored).
- Delete finished untracked doc docs/pr/PR-permea-explain-and-packaging.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The prior commit's tests/test_packaging_smoke.py claimed "CI installs the dev
extra", but the repo had no .github/workflows. The test skips whenever
`python -m build` is absent, so on the maintainer machine it skipped and ran
nowhere else -- it guarded nothing and that comment was not verifiable. This
adds the CI that makes the claim true.

Audit (Phase A): the suite is fully offline -- no test makes a live LLM provider
call and none requires a secret. The provider tests clear/monkeypatch
PERMEA_LLM_* and use fakes; test_explain_provider_configured is "strictly
offline" by construction; test_explain_boundary asserts openai/anthropic/httpx
are NOT imported. So CI needs no secrets.

Findings while wiring CI (pip install ".[dev]" alone could not even COLLECT the
suite):
- The test suite imports feature-extra deps unconditionally (fastapi in
  test_ui_drylab, jsonschema in several test_explain_*), and PyYAML -- an
  OPTIONAL runtime dep of permea_core guarded behind `try: import yaml` -- is
  declared in no extra at all. With only `.[dev]` these produced 14 collection
  errors, not skips.
- Fix: make `dev` a self-referential superset -- `permea-core[explain,ui]` plus
  pyyaml plus build/twine/pytest -- so `pip install .[dev]` yields an
  environment that can run the ENTIRE suite in one command. Base `dependencies`
  are untouched: PyYAML stays optional for CLI users; the diagnose path never
  needs it.

Changes:
- .github/workflows/ci.yml: CI on pull_request + push to main, ubuntu-latest,
  matrix over Python 3.11/3.12/3.13 (per requires-python >=3.11). Steps:
  checkout, setup-python, `pip install ".[dev]"`, then two pytest steps --
  `-m "not packaging"` (fast) and `-m packaging` (the wheel build/install test,
  kept separate so a packaging regression is distinguishable in the log). No
  secrets; only actions/checkout and actions/setup-python.
- pyproject.toml: expand the `dev` extra as above.
- tests/test_packaging_smoke.py: the "CI installs the dev extra" statement is now
  true (workflow added); docstring now states plainly that the test SKIPS when
  `python -m build` is unavailable, so a green local run does not imply it ran,
  and points at the CI workflow where it actually executes. Test not weakened.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@Permea-lab-admin
Permea-lab-admin merged commit 0a55a88 into main Jul 25, 2026
3 checks passed
@Permea-lab-admin
Permea-lab-admin deleted the feat/packaging-hardening branch July 25, 2026 13:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant