From 5e4d615da5a128d8fb55ad0542e7e83ca21cdc69 Mon Sep 17 00:00:00 2001 From: Tristan Simas Date: Thu, 1 Oct 2026 23:46:29 -0400 Subject: [PATCH] Fix publisher source admission and declare ROI dev dependency for 0.3.1 --- .github/workflows/publish.yml | 2 +- .../COMMANDS.rst | 38 +++++++++ .../RECEIPT.rst | 73 ++++++++++++++++++ .../admission.xml | 1 + .../focused-originals.xml | 1 + .../original-job-110690882405.log.gz | Bin 0 -> 25059 bytes .../qualified-source.txt | 4 + .../qualified.xml | 1 + pyproject.toml | 3 +- tests/test_publisher_admission.py | 39 ++++++++++ 10 files changed, 160 insertions(+), 2 deletions(-) create mode 100644 docs/validation/publisher-admission-031-20261002/COMMANDS.rst create mode 100644 docs/validation/publisher-admission-031-20261002/RECEIPT.rst create mode 100644 docs/validation/publisher-admission-031-20261002/admission.xml create mode 100644 docs/validation/publisher-admission-031-20261002/focused-originals.xml create mode 100644 docs/validation/publisher-admission-031-20261002/original-job-110690882405.log.gz create mode 100644 docs/validation/publisher-admission-031-20261002/qualified-source.txt create mode 100644 docs/validation/publisher-admission-031-20261002/qualified.xml create mode 100644 tests/test_publisher_admission.py diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index d5ca344..6d36abb 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -32,7 +32,7 @@ jobs: - name: Install build dependencies run: | python -m pip install --upgrade pip - python -m pip install build "twine>=7,<8" ".[dev]" + python -m pip install build "twine>=7,<8" -e ".[dev]" - name: Test release candidate run: python -m pytest -q diff --git a/docs/validation/publisher-admission-031-20261002/COMMANDS.rst b/docs/validation/publisher-admission-031-20261002/COMMANDS.rst new file mode 100644 index 0000000..fcf8a46 --- /dev/null +++ b/docs/validation/publisher-admission-031-20261002/COMMANDS.rst @@ -0,0 +1,38 @@ +Focused qualification command +============================= + +Run from the isolated PolyStore worktree:: + + systemd-run --user --scope --quiet \ + -p MemoryMax=512M -p MemorySwapMax=0 -p CPUQuota=100% \ + timeout 60s taskset -c 0 env \ + PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 PYTHONDONTWRITEBYTECODE=1 \ + OPENBLAS_NUM_THREADS=1 OMP_NUM_THREADS=1 MKL_NUM_THREADS=1 \ + PYTHONPATH=/home/ts/wt/polystore-publisher-admission-031-20261002/src \ + /home/ts/wt/openhcs-generated-inputs-installed-parent-20261001/.venv/bin/python -B \ + /home/ts/wt/openhcs-prior-measurement-role-projection-20261001/docs/validation/selected_plane_stream_materialization_20261001/run_bounded_source.py \ + /home/ts/wt/openhcs-generated-inputs-installed-parent-20261001/.venv/bin/python -B -m pytest \ + -o addopts= \ + --basetemp=docs/validation/publisher-admission-031-20261002/qualified-test-temp \ + --junitxml=docs/validation/publisher-admission-031-20261002/qualified.xml \ + tests/test_publisher_admission.py tests/test_basic.py \ + tests/test_imagej_cache_environment.py tests/test_metadata_namespace.py \ + tests/test_roi_region_properties.py tests/test_roi.py \ + tests/test_lazy_package_exports.py -q + +The default coverage/report addopts are disabled for this focused resource-bound +source run, not for the publisher. All selected tests/assertions are unchanged. +Source fixtures prohibit actual Fiji downloads/JVM execution. + +Offline lock attempt (terminal failure):: + + systemd-run --user --scope --quiet \ + -p MemoryMax=512M -p MemorySwapMax=0 -p CPUQuota=100% \ + timeout 60s taskset -c 0 uv lock --offline --no-python-downloads + +No solution for python_full_version >=3.14 / win32: imglyb not found in cache; +polystore[all] requires imglyb==2.1.0. No lock file was changed. + +Owned disposable output is confined to the three source-test-temp, +admission-test-temp and qualified-test-temp directories below this receipt root. +Original log, test XML and qualification notes are durable evidence, not caches. diff --git a/docs/validation/publisher-admission-031-20261002/RECEIPT.rst b/docs/validation/publisher-admission-031-20261002/RECEIPT.rst new file mode 100644 index 0000000..b581a23 --- /dev/null +++ b/docs/validation/publisher-admission-031-20261002/RECEIPT.rst @@ -0,0 +1,73 @@ +PolyStore 0.3.1 publisher admission +================================ + +Source base: 84f322e46871de5ed47e7fd20976ad03e533c1c4 (remote main). +Owner: Dewey, isolated polystore-publisher-admission-031-20261002 worktree. +Parent owns integration, the sole new 0.3.1 tag, and hosted release acceptance. +The immutable failed v0.3.0 tag is untouched. + +Original failure +---------------- + +Run https://github.com/OpenHCSDev/PolyStore/actions/runs/36959840684, +job 110690882405: 9 failed, 545 passed, 19 skipped in 15.91s. +Three failures require child processes to import checkout source; the publisher +installed a regular distribution. Six ROI topology/archive cases fail because +the existing dev extra omitted roifile. No original test or skip is changed. + +The full job log was fetched through the GitHub SDK job-log tool and archived +as original-job-110690882405.log.gz (lossless gzip), preserving UTF-8 text including +its original BOM and final newline: 142020 bytes, SHA256 +542d75ef00bcd8677526131a1afe195cea6fa63edca7eca5aa8e0b1b4e4b703c. + +Ownership and repair +-------------------- + +Replace the existing publisher install with editable .[dev] admission, matching +the existing ordinary test workflow. The later package build and immutable +declaration/publish steps are unchanged. Declare roifile in the original dev +extra, not a workflow-only dependency roster or mandatory runtime requirement. +Advance the sole project version declaration to 0.3.1; the existing package +version and release scripts derive it from distribution/project metadata. + +Current NRA/refactor-audit skills and packaged pattern catalog were read. +MEMB-1/MEMB-2: dependency membership remains in the original extras declaration. +TIME-8: no duplicated version or metadata authority. No Python runtime mechanism +is introduced, so inheritance/MI would be ornamental here. Independent future +dev dependencies need only their own extra entry, not publisher consumer edits. +The real editable-build test reads emitted metadata and the actual source .pth +from the existing setuptools backend rather than mirroring its implementation. + +Open-PR check found only Dependabot PR10, whose publisher-file changes are action +pins; this patch leaves those pins unchanged. Parent's release worktree is not +edited. No environment installation, external download, Fiji/native launch, +science job, tag or release operation was performed. + +Focused source qualification +---------------------------- + +68 PASS, zero skips: publisher admission/editable metadata, basic package, +ImageJ cache policy and fresh-process source, namespace handoff, ROI geometry +and archive roundtrip, and lazy package exports. These include all nine original +failed cases. The initial original-only run was 63 PASS; new admission controls +were 2 PASS. Final combined run: 8.43s pytest, 9.089s monitored wall, +322700 KiB aggregate RSS (315.14 MiB), one CPU, 512 MiB / 60s limits. +See qualified.xml and qualified-source.txt. The command is in COMMANDS.rst. + +Source is explicitly this worktree's src; dependencies/interpreter are readonly +openhcs-generated-inputs-installed-parent-20261001/.venv/bin/python. +The two publisher controls exercise the real offline editable build without +installing its artifact. They verify checkout binding, unfiltered publisher +pytest invocation, derived version, and dev-only ROI dependency metadata. +No installed editable-candidate or hosted 0.3.1 acceptance is claimed. + +Lock limitation +--------------- + +uv lock --offline --no-python-downloads failed because imglyb==2.1.0 is absent +from the cache for the all/bioformats extras. Original uv.lock already records +PolyStore 0.2.18 and ZMQRuntime 0.2.21, inconsistent with base declarations. +The lock is unchanged: no fabricated entries, constrained platforms, dependency +weakening or downloads. Publisher pip does not consume uv.lock. The existing +separate distribution CI lock-check remains unqualified until authorized lock +regeneration; this is not represented as publisher or runtime acceptance. diff --git a/docs/validation/publisher-admission-031-20261002/admission.xml b/docs/validation/publisher-admission-031-20261002/admission.xml new file mode 100644 index 0000000..b39cf3a --- /dev/null +++ b/docs/validation/publisher-admission-031-20261002/admission.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/validation/publisher-admission-031-20261002/focused-originals.xml b/docs/validation/publisher-admission-031-20261002/focused-originals.xml new file mode 100644 index 0000000..3285ae2 --- /dev/null +++ b/docs/validation/publisher-admission-031-20261002/focused-originals.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/validation/publisher-admission-031-20261002/original-job-110690882405.log.gz b/docs/validation/publisher-admission-031-20261002/original-job-110690882405.log.gz new file mode 100644 index 0000000000000000000000000000000000000000..f3791150d925ecdb29b578f3c8327bd128167ff3 GIT binary patch literal 25059 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�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 \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index 40692cb..2bc2ee6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "polystore" -version = "0.3.0" +version = "0.3.1" description = "Framework-agnostic multi-backend storage abstraction for ML and scientific computing" readme = "README.md" requires-python = ">=3.11" @@ -101,6 +101,7 @@ dev = [ "genbadge[coverage]", "pandas>=2.3.1", "jpype1>=1.4.0", + "roifile", "black>=23.0.0", "ruff>=0.1.0", ] diff --git a/tests/test_publisher_admission.py b/tests/test_publisher_admission.py new file mode 100644 index 0000000..fcec273 --- /dev/null +++ b/tests/test_publisher_admission.py @@ -0,0 +1,39 @@ +"""Release tests use the checkout; the built distribution owns its metadata.""" + +import shlex +import tomllib +import zipfile +from email.parser import Parser +from pathlib import Path + +from packaging.requirements import Requirement +from setuptools import build_meta + + +ROOT = Path(__file__).resolve().parents[1] + + +def test_publisher_installs_the_dev_candidate_editably(): + workflow = (ROOT / ".github/workflows/publish.yml").read_text() + commands = [shlex.split(line.strip()) for line in workflow.splitlines()] + (install,) = [command for command in commands if ".[dev]" in command] + assert install[:4] == ["python", "-m", "pip", "install"] + assert install[install.index("-e") + 1] == ".[dev]" + assert "run: python -m pytest -q" in workflow + + +def test_editable_artifact_owns_checkout_path_and_roi_dev_requirement(tmp_path, monkeypatch): + monkeypatch.chdir(ROOT) + wheel = build_meta.build_editable(str(tmp_path)) + with zipfile.ZipFile(tmp_path / wheel) as archive: + (pth,) = [name for name in archive.namelist() if name.endswith(".pth")] + assert Path(archive.read(pth).decode().strip()).resolve() == ROOT / "src" + (metadata_name,) = [name for name in archive.namelist() if name.endswith("/METADATA")] + metadata = Parser().parsestr(archive.read(metadata_name).decode()) + project = tomllib.loads((ROOT / "pyproject.toml").read_text())["project"] + assert metadata["Name"] == project["name"] + assert metadata["Version"] == project["version"] + requirements = [Requirement(value) for value in metadata.get_all("Requires-Dist")] + (roi,) = [requirement for requirement in requirements if requirement.name == "roifile"] + assert roi.marker.evaluate({"extra": "dev"}) + assert not roi.marker.evaluate({"extra": ""})