diff --git a/docs/validation/saved-label-plane-domain-419-20261002/COMMANDS.rst b/docs/validation/saved-label-plane-domain-419-20261002/COMMANDS.rst new file mode 100644 index 0000000000..385c712a83 --- /dev/null +++ b/docs/validation/saved-label-plane-domain-419-20261002/COMMANDS.rst @@ -0,0 +1,84 @@ +Exact source commands and provenance +==================================== + +Working directory for all commands: +/home/ts/wt/openhcs-prior-measurement-role-projection-20261001. +No command operates a live application, changes an installed environment, +downloads dependencies, reads scientific arrays or removes existing files. + +Original red and geometry/adjacent/distance source shards share this invocation:: + + systemd-run --user --scope --quiet -p MemoryMax=512M -p MemorySwapMax=0 \ + -p CPUQuota=100% timeout 60s taskset -c 0 env \ + OPENHCS_SOURCE_TEST_ROOT=/home/ts/wt/openhcs-prior-measurement-role-projection-20261001 \ + PYTHONPATH=/home/ts/wt/openhcs-prior-measurement-role-projection-20261001 \ + PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 OPENHCS_CPU_ONLY=true \ + OPENBLAS_NUM_THREADS=1 OMP_NUM_THREADS=1 MKL_NUM_THREADS=1 NUMBA_NUM_THREADS=1 \ + PYTHONDONTWRITEBYTECODE=1 \ + /home/ts/wt/openhcs-generated-inputs-installed-parent-20261001/.venv/bin/python -B \ + docs/validation/selected_plane_stream_materialization_20261001/run_bounded_source.py \ + /home/ts/wt/openhcs-generated-inputs-installed-parent-20261001/.venv/bin/python -B \ + docs/validation/compiled_metadata_artifact_binding_368_20261001/source_shard.py \ + -q -p no:cacheprovider --junitxml= + +Each invocation redirects stdout/stderr to the distinct matching .log; originals +are never reused/overwritten. Targets: + +* original-red: tests/unit/test_saved_source_label_plane_domain.py on unchanged + production base c32447f1, first authored fixture. +* geometry-focused: same target after only the builder correction. +* geometry-focused-corrected: same target after identity() fixture correction. +* geometry-and-runtime-values: tests/unit/test_saved_source_label_plane_domain.py + tests/unit/test_runtime_values.py after correcting original ROW_SEQUENCE ABI + expectation and adding the genuine per-plane-volume control. +* adjacent-controls: tests/unit/test_cellprofiler_image_output_metadata.py + tests/unit/test_source_spatial_domain.py tests/unit/test_cellprofiler_shape_hotpath.py. +* distance-original-red: validation/reproduce_saved_label_distance_419.py. +* projection-owner-controls and final-owner-controls: all five unit files + above (saved_source_label_plane_domain, runtime_values, image_output_metadata, + source_spatial_domain, shape_hotpath). Final adds the paired-projection + cooperative capability cases. Both commands have distinct log/XML paths. + +Original R0 source is loaded directly from retained Git, never copied or changed:: + + systemd-run --user --scope --quiet -p MemoryMax=512M -p MemorySwapMax=0 \ + -p CPUQuota=100% timeout 60s taskset -c 0 env PYTHONDONTWRITEBYTECODE=1 \ + OMP_NUM_THREADS=1 OPENBLAS_NUM_THREADS=1 MKL_NUM_THREADS=1 \ + /home/ts/.local/share/uv/python/cpython-3.14-linux-x86_64-gnu/bin/python3.14 \ + -I -B validation/run_pinned_r0_419.py --root openhcs \ + --base c32447f1c86a1878a313d1643a398e30ac20f75e \ + --head e6fc6ad834193df5080fca1c48fa4cbd22576cdd + +That working production checkpoint is REJECTED by the original guard. Its +lossless output is r0-original-pin.log.gz, verified against the retained local +original using gzip -cd | cmp. No replacement detector was used. + +The requested owner proposal is not applied to production or another WT:: + + git apply --check docs/validation/saved-label-plane-domain-419-20261002/metadata-owner-proposal.patch + GIT_INDEX_FILE= git read-tree e6fc6ad834193df5080fca1c48fa4cbd22576cdd + GIT_INDEX_FILE= git apply --cached docs/validation/saved-label-plane-domain-419-20261002/metadata-owner-proposal.patch + GIT_INDEX_FILE= git write-tree + +Tree aa0d5552a2761f5a7ee07190f27064563ecb5a98 was initially submitted to original +R0; it correctly rejected a non-commit revision. That failed command/log remain. +An isolated Git object (no branch/worktree changes) then gives it a commit:: + + git commit-tree aa0d5552a2761f5a7ee07190f27064563ecb5a98 \ + -p e6fc6ad834193df5080fca1c48fa4cbd22576cdd \ + -m 'Unapplied #419 metadata-owner proposal for source guard only' + +Result 566238fd230dd1f7e5b7861fe7702772a45da7e5 is the head of the separate +original-R0 proposal command (same invocation above, only --head differs). +It is NOT the PR branch or an installed source. Source behavior for this +unapplied shared-owner hook remains pending receiving-owner integration. + +This metadata proposal was subsequently REJECTED: original R0 reports god-class +growth10. It is not the current requested correction. Current production uses +the existing RuntimePlaneAxisValueProjection constructor outside PR394's seams. +Actual production e6fde72ae is tested with the original command above, substituting +that head and inserting the existing run_bounded_source.py monitor between the +outer Python3.14 and the inner Python3.14 invocation. Output is retained in +r0-final-production.log.gz: zero positive deltas / exit0 / aggregate95584KiB / +18.286s. The source controls are 211 PASS / aggregate418932KiB / 9.629s. +No command modifies PR394's files or applies the rejected metadata proposal. diff --git a/docs/validation/saved-label-plane-domain-419-20261002/RECEIPT.rst b/docs/validation/saved-label-plane-domain-419-20261002/RECEIPT.rst new file mode 100644 index 0000000000..492dc048d7 --- /dev/null +++ b/docs/validation/saved-label-plane-domain-419-20261002/RECEIPT.rst @@ -0,0 +1,146 @@ +Saved label plane-domain source repair (#419) +=========================================== + +Owner: Dewey. Base: c32447f1c86a1878a313d1643a398e30ac20f75e. +Existing persistent worktree reused; previous branches and untracked evidence +are preserved. No new environment, installations or runtime/scientific jobs. + +Current owner correction: RuntimePlaneAxisValueProjection.from_source_declaration +constructs projection from the declared optional axis and original nominal +SourceImageProvenance. SourceImageObjectLabelBuildRequest consumes that proof. +The projection value already owns declaration-based constructors and canonical +preserve()/selection; no metadata hook, second registry or compatibility reader +is introduced. Both production files are outside PR394's listed shared seams. +The earlier rejected metadata-owner proposal below is historical, not required. + +SOURCE CHECKPOINT: production e6fde72ae qualified by final211 source controls +and original pinned R0 PASS with zero positive deltas. Subsequent receipt-only +publication preserves those exact production bytes. Parent owns installed +saved-label acceptance; the distinct Morph failure remains with PR394. + +Original failures remain in the parent-owned neurite-development-skill383 +evidence root. Geometry job 7ff51e34-b98f-4d56-953d-2ea32dba612a and distance +job 0f9f7236-ae18-440b-bedf-1dfa2946c427 are not replayed or reclassified. + +Production owner: SourceImageObjectLabelBuildRequest.plane_semantics. This +existing builder must retain the input's explicit nominal plane-axis and exact +source-plane cardinality, not infer spatial dimensionality from array rank. +Existing ObjectLabelPlaneDomainStrategy and registered shape kernels continue +to own projection and geometry. No new registry or copied geometry. + +Patterns reviewed from the current NRA/refactor-audit package: IDEN-1, +BOUND-2 and IMPL-13. A new PhysicalCalibrationRequired admission capability +composes through cooperative super() with the original builder; it exercises +actual acceptance/rejection and per-plane building, not only MRO assertions. + +PR394 retains its runtime/CellProfiler files. Minimal canonical raw-call ABI +request is published at PR394 issuecomment-5944804885. Morph DISTANCE is a +separate unresolved shared invocation boundary, not fixed by this builder. +Installed/native original saved-label acceptance remains parent-owned. + +Bounded source evidence +----------------------- + +Original unchanged-main reproducer: 9 failed / 1 passed, 5.371s, +329084KiB aggregate RSS. original-red.log/xml remain unchanged. The first +corrected runs exposed two invalid test assumptions: comparing bound identity +methods rather than their returned identities, and expecting two sparse-ID rows +from the original AreaShape ROW_SEQUENCE/dense-extent ABI. Those runs remain +in geometry-focused and geometry-focused-corrected logs/XML. The final test +calls the original identity owner and checks the entire 135-entry AreaShape +vector, including every NaN slot, alongside exact input IDs/pixels/provenance. +This is not a claim that public final measurement rows have sparse-label IDs. + +Current synthetic original-entrypoint and existing runtime-value controls: +192 passed, 7.882s / 392288KiB aggregate RSS. geometry-and-runtime-values.log/xml +retain all output. Existing registered MeasureObjectSizeShape resolves through +CallableContract and the original FULL_STACK executor, now consuming two +declared 2-D planes with XY1.3556 and correct native pixel areas 6 and 12. +Both original runtime axis declarations, singleton source, genuine volume +within each declared plane, explicit payload override, undeclared volume, +missing/conflicting cardinality, geometry conflict, payload-wide ID rejection, +explicit axis conflict and cooperative calibrated-leaf admission are covered. + +Each shard uses systemd MemoryMax512M / MemorySwapMax0 / CPUQuota100%, +taskset CPU0, outer timeout60s and the existing aggregate-RSS monitor. Python +is the read-only generated-inputs-installed-parent interpreter; source root +is this worktree. Existing source_shard.py borrows only the two installed ABI +extensions and asserts source import ownership. No application processes, +compiled scientific jobs, installs or package changes are performed. + +Adjacent original controls: 17 passed, 7.000s / 409400KiB aggregate RSS, covering +CellProfiler image-output metadata, source spatial domains and the unchanged +AreaShape hotpath (adjacent-controls.log/xml). Total source controls: 209 pass. + +The explicit original-executor Morph DISTANCE reproducer remains FAILED: +returned shape(1,) versus required(1,9,9), 5.026s / 327844KiB aggregate RSS. +This is an earlier original invocation witness, not a claim to reproduce the +later live module-output contextualization's exact shape(1,1) message. Both +original traces remain retained; the reproducer has no xfail or suppression. + +Original pinned R0 was recovered without a new worktree, extracted copy or +alternate detector: validation/run_pinned_r0_419.py uses importlib ABCs to read +original package modules on demand from retained agent-comms Git objects at +CI pin3b03785f45df2ef5dc62ba6aed99294192ecbb01. The detector blob SHA256 is +e323c94d49c2b72d9524a5169f123e64b4a6e46a41035ca9fb4497e49b6ca562. +Python3.14 and metaclass backing remain read-only. It REJECTS production +e6fc6ad83: ForeignAbsenceProbe on runtime_object_label_building.py increases +0 -> 1. Original output r0-original-pin.log is retained. No R0 PASS claimed. + +That rejected checkpoint names a real boundary violation: the builder asks whether +another owner's optional metadata plane_axis is present. The metadata owner +must instead report its complete projection. metadata-owner-proposal.patch +is an UNAPPLIED request, not a competing runtime edit: add the small original +ImagePayloadMetadata.preserved_plane_projection() owner hook and replace the +new builder probe/constructor with that call. It changes no existing singleton +hook behavior, raw output contract, enum/member roster, or scientific kernel. +The unmodified R0 also rejected the unapplied metadata hook: original +ImagePayloadMetadata GodClassExcess rises540 -> 550. The initial attempt to +submit its tree rather than a commit is separately retained as a failed command. +The proposal is rejected, not substituted into the current implementation. +Its remaining raw ndarray invocation correction belongs to PR394 independently. + +The current correction instead extends the EXISTING projection value's source +construction alongside from_projector. The optional declared axis is an explicit +constructor input, not a metadata presence fact re-decided by a consumer. +Cardinality/aliases derive from the original SourceImageProvenance, and original +preserve() validates them. Source builder delegates construction and keeps its +own domain/shape invariants. No new carrier, facade, mapping or roster is added. +The superseded probe/constructor in the builder is removed. Independent paired +source-admission capability composes with the actual projection value through +cooperative __post_init__/super; inherited source construction and selection +execute its hook, reject three sources, while the original projection accepts +the same three-source declaration. Generic consumers need no new leaf branch. + +Projection-owner controls before adding the new paired capability cases: +209 PASS, 8.771s / 416796KiB aggregate RSS (projection-owner-controls.log/xml). +Final211 source controls PASS, 9.629s / 418932KiB aggregate RSS +(final-owner-controls.log/xml). This includes both original declared axes in +the new cooperative paired-projection capability, inherited source construction +and selection, over-cardinality rejection and original unbounded acceptance. + +Original pinned R0 PASS on actual production e6fde72ae, base c32447f1: +all positive deltas zero, 18.286s / 95584KiB aggregate RSS, exit0. Both changed +production paths are admitted (runtime_object_label_building.py and +runtime_plane_projection.py). r0-final-production.log.gz preserves exact +original output; it is checked losslessly against the retained local log. +The original source pin, Python3.14, original detector and budgets are unchanged. +No guard exception, count reuse, new detector or shared metadata edit is used. + +R1 full-context qualification is not claimed. This reused source worktree's +eight recorded dependencies are uninitialized; the original SourceRevision +require_repository guard rejects parent-repository resolution. A reduced +context scan or retained counts would not qualify the original R1 contract. +No full heavyweight gate is started within the source60s boundary. + +Original plan hashes (read-only, not copied data stores): +geometry-plan-4.py dd00bdcef3fdc101a4aaf533ed2897086ead605918849f55070ee2d22b20e4d0; +distance-plan-2.py 3fefcf9113143728b98db2ba1a23e40b60625a60ee717958f0e20c44ad8f3c31. +Frozen public388 driver still has original SHA256 +d3f259fae72ed5f70117646befa6b68a8301e168d785a7a56159cce1726bfd23. + +Remaining acceptance: receiving PR394 owner settles raw invocation seam, +then parent-installed original saved-label +geometry/EDT acceptance. Full-context R1 remains a separate unqualified scope. +Geometry source checkpoint is qualified for parent review/integration; +no installed/biological readiness or original issue closure is claimed. diff --git a/docs/validation/saved-label-plane-domain-419-20261002/adjacent-controls.log b/docs/validation/saved-label-plane-domain-419-20261002/adjacent-controls.log new file mode 100644 index 0000000000..217db11662 --- /dev/null +++ b/docs/validation/saved-label-plane-domain-419-20261002/adjacent-controls.log @@ -0,0 +1,21 @@ +Read-only native ABI: /home/ts/wt/openhcs-paired-raw-installed-parent-20261001/.venv/lib/python3.12/site-packages/openhcs/core/_tabular_native.abi3.so e1e0517b3706e6f6e8de126e8c3758c3a6bbf0ca024782b795fcb27d509f3e3e +Read-only native ABI: /home/ts/wt/openhcs-paired-raw-installed-parent-20261001/.venv/lib/python3.12/site-packages/openhcs/processing/backends/cellprofiler/_granularity_native.abi3.so 9f873070c3e136dd78109a55570852981e989c1d21e3452ce214bbaa753b7308 +Source owner: /home/ts/wt/openhcs-prior-measurement-role-projection-20261001/openhcs/core/function_patterns.py +Source owner: /home/ts/wt/openhcs-prior-measurement-role-projection-20261001/openhcs/core/pipeline/path_planner.py +Source owner: /home/ts/wt/openhcs-prior-measurement-role-projection-20261001/openhcs/core/steps/function_runtime.py +................. [100%] +=============================== warnings summary =============================== +../../code/projects/openhcs/.venv/lib/python3.12/site-packages/_pytest/config/__init__.py:1441 + /home/ts/code/projects/openhcs/.venv/lib/python3.12/site-packages/_pytest/config/__init__.py:1441: PytestConfigWarning: Unknown config option: asyncio_default_fixture_loop_scope + + self._warn_or_fail_if_strict(f"Unknown config option: {key}\n") + +../../code/projects/openhcs/.venv/lib/python3.12/site-packages/_pytest/config/__init__.py:1441 + /home/ts/code/projects/openhcs/.venv/lib/python3.12/site-packages/_pytest/config/__init__.py:1441: PytestConfigWarning: Unknown config option: asyncio_mode + + self._warn_or_fail_if_strict(f"Unknown config option: {key}\n") + +-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html +- generated xml file: /home/ts/wt/openhcs-prior-measurement-role-projection-20261001/docs/validation/saved-label-plane-domain-419-20261002/adjacent-controls.xml - +17 passed, 2 warnings in 3.45s +BOUNDED_SOURCE peak_aggregate_rss_kib=409400 elapsed_seconds=7.000 returncode=0 reason=None diff --git a/docs/validation/saved-label-plane-domain-419-20261002/adjacent-controls.xml b/docs/validation/saved-label-plane-domain-419-20261002/adjacent-controls.xml new file mode 100644 index 0000000000..88de603f55 --- /dev/null +++ b/docs/validation/saved-label-plane-domain-419-20261002/adjacent-controls.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/validation/saved-label-plane-domain-419-20261002/distance-original-red.log b/docs/validation/saved-label-plane-domain-419-20261002/distance-original-red.log new file mode 100644 index 0000000000..0935b82fd8 --- /dev/null +++ b/docs/validation/saved-label-plane-domain-419-20261002/distance-original-red.log @@ -0,0 +1,53 @@ +Read-only native ABI: /home/ts/wt/openhcs-paired-raw-installed-parent-20261001/.venv/lib/python3.12/site-packages/openhcs/core/_tabular_native.abi3.so e1e0517b3706e6f6e8de126e8c3758c3a6bbf0ca024782b795fcb27d509f3e3e +Read-only native ABI: /home/ts/wt/openhcs-paired-raw-installed-parent-20261001/.venv/lib/python3.12/site-packages/openhcs/processing/backends/cellprofiler/_granularity_native.abi3.so 9f873070c3e136dd78109a55570852981e989c1d21e3452ce214bbaa753b7308 +Source owner: /home/ts/wt/openhcs-prior-measurement-role-projection-20261001/openhcs/core/function_patterns.py +Source owner: /home/ts/wt/openhcs-prior-measurement-role-projection-20261001/openhcs/core/pipeline/path_planner.py +Source owner: /home/ts/wt/openhcs-prior-measurement-role-projection-20261001/openhcs/core/steps/function_runtime.py +F [100%] +=================================== FAILURES =================================== +_______ test_original_registered_distance_raw_abi_keeps_planar_geometry ________ + + def test_original_registered_distance_raw_abi_keeps_planar_geometry(): + labels = np.zeros((1, 9, 9), dtype=np.int32) + labels[0, 2:7, 2:7] = 29 + original = labels.copy() + source = ImagePayloadMetadata( + plane_axis=RuntimePlaneAxis.RUNTIME_SLICE, + source_image_names=("saved_foreground",), + source_image_provenance_planes=SourceImageProvenancePlanes.from_components( + paths=("/synthetic/A01_s001_w2_labels.tif",), + component_metadata=({"well": "A01", "site": "1", "channel": "2"},), + ), + source_voxel_spacing=SourceVoxelSpacing((1.3556, 1.3556)), + ).payload_with(labels, None) + contract = CallableContract.from_callable(morph) + result = CellProfilerFunctionContractExecutor().execute( + contract, contract.resolve_canonical_raw_callable(), source, + {"operation": MorphOperation.DISTANCE, "repeat_mode": RepeatMode.ONCE, "rescale_values": False}, + execution_mode=ImagePayloadExecutionMode.NATURAL, + ) + pixels = image_payload_data(result) +> assert pixels.shape == labels.shape +E assert (1,) == (1, 9, 9) +E +E Right contains 2 more items, first extra item: 9 +E Use -v to get more diff + +validation/reproduce_saved_label_distance_419.py:42: AssertionError +=============================== warnings summary =============================== +../../code/projects/openhcs/.venv/lib/python3.12/site-packages/_pytest/config/__init__.py:1441 + /home/ts/code/projects/openhcs/.venv/lib/python3.12/site-packages/_pytest/config/__init__.py:1441: PytestConfigWarning: Unknown config option: asyncio_default_fixture_loop_scope + + self._warn_or_fail_if_strict(f"Unknown config option: {key}\n") + +../../code/projects/openhcs/.venv/lib/python3.12/site-packages/_pytest/config/__init__.py:1441 + /home/ts/code/projects/openhcs/.venv/lib/python3.12/site-packages/_pytest/config/__init__.py:1441: PytestConfigWarning: Unknown config option: asyncio_mode + + self._warn_or_fail_if_strict(f"Unknown config option: {key}\n") + +-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html +- generated xml file: /home/ts/wt/openhcs-prior-measurement-role-projection-20261001/docs/validation/saved-label-plane-domain-419-20261002/distance-original-red.xml - +=========================== short test summary info ============================ +FAILED validation/reproduce_saved_label_distance_419.py::test_original_registered_distance_raw_abi_keeps_planar_geometry +1 failed, 2 warnings in 1.81s +BOUNDED_SOURCE peak_aggregate_rss_kib=327844 elapsed_seconds=5.026 returncode=1 reason=None diff --git a/docs/validation/saved-label-plane-domain-419-20261002/distance-original-red.xml b/docs/validation/saved-label-plane-domain-419-20261002/distance-original-red.xml new file mode 100644 index 0000000000..1b50b9250c --- /dev/null +++ b/docs/validation/saved-label-plane-domain-419-20261002/distance-original-red.xml @@ -0,0 +1,27 @@ +def test_original_registered_distance_raw_abi_keeps_planar_geometry(): + labels = np.zeros((1, 9, 9), dtype=np.int32) + labels[0, 2:7, 2:7] = 29 + original = labels.copy() + source = ImagePayloadMetadata( + plane_axis=RuntimePlaneAxis.RUNTIME_SLICE, + source_image_names=("saved_foreground",), + source_image_provenance_planes=SourceImageProvenancePlanes.from_components( + paths=("/synthetic/A01_s001_w2_labels.tif",), + component_metadata=({"well": "A01", "site": "1", "channel": "2"},), + ), + source_voxel_spacing=SourceVoxelSpacing((1.3556, 1.3556)), + ).payload_with(labels, None) + contract = CallableContract.from_callable(morph) + result = CellProfilerFunctionContractExecutor().execute( + contract, contract.resolve_canonical_raw_callable(), source, + {"operation": MorphOperation.DISTANCE, "repeat_mode": RepeatMode.ONCE, "rescale_values": False}, + execution_mode=ImagePayloadExecutionMode.NATURAL, + ) + pixels = image_payload_data(result) +> assert pixels.shape == labels.shape +E assert (1,) == (1, 9, 9) +E +E Right contains 2 more items, first extra item: 9 +E Use -v to get more diff + +validation/reproduce_saved_label_distance_419.py:42: AssertionError \ No newline at end of file diff --git a/docs/validation/saved-label-plane-domain-419-20261002/final-owner-controls.log b/docs/validation/saved-label-plane-domain-419-20261002/final-owner-controls.log new file mode 100644 index 0000000000..0633afc7cd --- /dev/null +++ b/docs/validation/saved-label-plane-domain-419-20261002/final-owner-controls.log @@ -0,0 +1,23 @@ +Read-only native ABI: /home/ts/wt/openhcs-paired-raw-installed-parent-20261001/.venv/lib/python3.12/site-packages/openhcs/core/_tabular_native.abi3.so e1e0517b3706e6f6e8de126e8c3758c3a6bbf0ca024782b795fcb27d509f3e3e +Read-only native ABI: /home/ts/wt/openhcs-paired-raw-installed-parent-20261001/.venv/lib/python3.12/site-packages/openhcs/processing/backends/cellprofiler/_granularity_native.abi3.so 9f873070c3e136dd78109a55570852981e989c1d21e3452ce214bbaa753b7308 +Source owner: /home/ts/wt/openhcs-prior-measurement-role-projection-20261001/openhcs/core/function_patterns.py +Source owner: /home/ts/wt/openhcs-prior-measurement-role-projection-20261001/openhcs/core/pipeline/path_planner.py +Source owner: /home/ts/wt/openhcs-prior-measurement-role-projection-20261001/openhcs/core/steps/function_runtime.py +........................................................................ [ 34%] +........................................................................ [ 68%] +................................................................... [100%] +=============================== warnings summary =============================== +../../code/projects/openhcs/.venv/lib/python3.12/site-packages/_pytest/config/__init__.py:1441 + /home/ts/code/projects/openhcs/.venv/lib/python3.12/site-packages/_pytest/config/__init__.py:1441: PytestConfigWarning: Unknown config option: asyncio_default_fixture_loop_scope + + self._warn_or_fail_if_strict(f"Unknown config option: {key}\n") + +../../code/projects/openhcs/.venv/lib/python3.12/site-packages/_pytest/config/__init__.py:1441 + /home/ts/code/projects/openhcs/.venv/lib/python3.12/site-packages/_pytest/config/__init__.py:1441: PytestConfigWarning: Unknown config option: asyncio_mode + + self._warn_or_fail_if_strict(f"Unknown config option: {key}\n") + +-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html +- generated xml file: /home/ts/wt/openhcs-prior-measurement-role-projection-20261001/docs/validation/saved-label-plane-domain-419-20261002/final-owner-controls.xml - +211 passed, 2 warnings in 5.39s +BOUNDED_SOURCE peak_aggregate_rss_kib=418932 elapsed_seconds=9.629 returncode=0 reason=None diff --git a/docs/validation/saved-label-plane-domain-419-20261002/final-owner-controls.xml b/docs/validation/saved-label-plane-domain-419-20261002/final-owner-controls.xml new file mode 100644 index 0000000000..1af5068e03 --- /dev/null +++ b/docs/validation/saved-label-plane-domain-419-20261002/final-owner-controls.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/validation/saved-label-plane-domain-419-20261002/geometry-and-runtime-values.log b/docs/validation/saved-label-plane-domain-419-20261002/geometry-and-runtime-values.log new file mode 100644 index 0000000000..85672c40e5 --- /dev/null +++ b/docs/validation/saved-label-plane-domain-419-20261002/geometry-and-runtime-values.log @@ -0,0 +1,23 @@ +Read-only native ABI: /home/ts/wt/openhcs-paired-raw-installed-parent-20261001/.venv/lib/python3.12/site-packages/openhcs/core/_tabular_native.abi3.so e1e0517b3706e6f6e8de126e8c3758c3a6bbf0ca024782b795fcb27d509f3e3e +Read-only native ABI: /home/ts/wt/openhcs-paired-raw-installed-parent-20261001/.venv/lib/python3.12/site-packages/openhcs/processing/backends/cellprofiler/_granularity_native.abi3.so 9f873070c3e136dd78109a55570852981e989c1d21e3452ce214bbaa753b7308 +Source owner: /home/ts/wt/openhcs-prior-measurement-role-projection-20261001/openhcs/core/function_patterns.py +Source owner: /home/ts/wt/openhcs-prior-measurement-role-projection-20261001/openhcs/core/pipeline/path_planner.py +Source owner: /home/ts/wt/openhcs-prior-measurement-role-projection-20261001/openhcs/core/steps/function_runtime.py +........................................................................ [ 37%] +........................................................................ [ 75%] +................................................ [100%] +=============================== warnings summary =============================== +../../code/projects/openhcs/.venv/lib/python3.12/site-packages/_pytest/config/__init__.py:1441 + /home/ts/code/projects/openhcs/.venv/lib/python3.12/site-packages/_pytest/config/__init__.py:1441: PytestConfigWarning: Unknown config option: asyncio_default_fixture_loop_scope + + self._warn_or_fail_if_strict(f"Unknown config option: {key}\n") + +../../code/projects/openhcs/.venv/lib/python3.12/site-packages/_pytest/config/__init__.py:1441 + /home/ts/code/projects/openhcs/.venv/lib/python3.12/site-packages/_pytest/config/__init__.py:1441: PytestConfigWarning: Unknown config option: asyncio_mode + + self._warn_or_fail_if_strict(f"Unknown config option: {key}\n") + +-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html +- generated xml file: /home/ts/wt/openhcs-prior-measurement-role-projection-20261001/docs/validation/saved-label-plane-domain-419-20261002/geometry-and-runtime-values.xml - +192 passed, 2 warnings in 4.43s +BOUNDED_SOURCE peak_aggregate_rss_kib=392288 elapsed_seconds=7.882 returncode=0 reason=None diff --git a/docs/validation/saved-label-plane-domain-419-20261002/geometry-and-runtime-values.xml b/docs/validation/saved-label-plane-domain-419-20261002/geometry-and-runtime-values.xml new file mode 100644 index 0000000000..b711aac3c2 --- /dev/null +++ b/docs/validation/saved-label-plane-domain-419-20261002/geometry-and-runtime-values.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/validation/saved-label-plane-domain-419-20261002/geometry-focused-corrected.log b/docs/validation/saved-label-plane-domain-419-20261002/geometry-focused-corrected.log new file mode 100644 index 0000000000..67961abd2e --- /dev/null +++ b/docs/validation/saved-label-plane-domain-419-20261002/geometry-focused-corrected.log @@ -0,0 +1,105 @@ +Read-only native ABI: /home/ts/wt/openhcs-paired-raw-installed-parent-20261001/.venv/lib/python3.12/site-packages/openhcs/core/_tabular_native.abi3.so e1e0517b3706e6f6e8de126e8c3758c3a6bbf0ca024782b795fcb27d509f3e3e +Read-only native ABI: /home/ts/wt/openhcs-paired-raw-installed-parent-20261001/.venv/lib/python3.12/site-packages/openhcs/processing/backends/cellprofiler/_granularity_native.abi3.so 9f873070c3e136dd78109a55570852981e989c1d21e3452ce214bbaa753b7308 +Source owner: /home/ts/wt/openhcs-prior-measurement-role-projection-20261001/openhcs/core/function_patterns.py +Source owner: /home/ts/wt/openhcs-prior-measurement-role-projection-20261001/openhcs/core/pipeline/path_planner.py +Source owner: /home/ts/wt/openhcs-prior-measurement-role-projection-20261001/openhcs/core/steps/function_runtime.py +FF........ [100%] +=================================== FAILURES =================================== +_ test_original_artifact_admission_and_full_stack_shape_keep_2d_planes[runtime_slice] _ + +axis = + + @pytest.mark.parametrize("axis", tuple(RuntimePlaneAxis)) + def test_original_artifact_admission_and_full_stack_shape_keep_2d_planes(axis): + labels = np.zeros((2, 8, 9), dtype=np.int32) + labels[0, 1:3, 2:5] = 29 + labels[1, 2:5, 3:7] = 106 + source = _source(labels, axis=axis) + source_bytes = labels.tobytes() + spec = ArtifactSpec.input("saved_labels", ObjectLabelsArtifactType, parameter_name="labels") + value = RuntimeArtifactTypeStrategy.for_artifact_type(spec.artifact_type).runtime_input_value( + RuntimeArtifactInputRequest(spec=spec, value=source) + ) + assert value.domain.scope is ObjectLabelDomainScope.PLANE + assert value.plane_axis is axis + assert value.domain.declared_object_id_domains == ((29,), (106,)) + assert value.source_provenance.identity() == source.metadata.source_provenance.identity() + planes = value.measurement_planes() + assert tuple(plane.labels.shape for plane in planes) == ((8, 9), (8, 9)) + for index, plane in enumerate(planes): + np.testing.assert_array_equal(plane.labels, labels[index]) + assert plane.parent_image_source_voxel_spacing == SourceVoxelSpacing((1.3556, 1.3556)) + + contract = CallableContract.from_callable(measure_object_size_shape) + _image, rows = CellProfilerFunctionContractExecutor().execute( + contract, contract.resolve_canonical_raw_callable(), source, + {"labels": value, "calculate_advanced": False, "calculate_zernikes": False}, + execution_mode=ImagePayloadExecutionMode.FULL_STACK, + ) + area = MeasureObjectSizeShapeModule.MeasurementFeature.AREA.value +> assert tuple(row[area] for row in rows) == (6.0, 12.0) +E assert (6.0, nan, na...nan, nan, ...) == (6.0, 12.0) +E +E At index 1 diff: nan != 12.0 +E Left contains 133 more items, first extra item: nan +E Use -v to get more diff + +tests/unit/test_saved_source_label_plane_domain.py:65: AssertionError +_ test_original_artifact_admission_and_full_stack_shape_keep_2d_planes[source_binding] _ + +axis = + + @pytest.mark.parametrize("axis", tuple(RuntimePlaneAxis)) + def test_original_artifact_admission_and_full_stack_shape_keep_2d_planes(axis): + labels = np.zeros((2, 8, 9), dtype=np.int32) + labels[0, 1:3, 2:5] = 29 + labels[1, 2:5, 3:7] = 106 + source = _source(labels, axis=axis) + source_bytes = labels.tobytes() + spec = ArtifactSpec.input("saved_labels", ObjectLabelsArtifactType, parameter_name="labels") + value = RuntimeArtifactTypeStrategy.for_artifact_type(spec.artifact_type).runtime_input_value( + RuntimeArtifactInputRequest(spec=spec, value=source) + ) + assert value.domain.scope is ObjectLabelDomainScope.PLANE + assert value.plane_axis is axis + assert value.domain.declared_object_id_domains == ((29,), (106,)) + assert value.source_provenance.identity() == source.metadata.source_provenance.identity() + planes = value.measurement_planes() + assert tuple(plane.labels.shape for plane in planes) == ((8, 9), (8, 9)) + for index, plane in enumerate(planes): + np.testing.assert_array_equal(plane.labels, labels[index]) + assert plane.parent_image_source_voxel_spacing == SourceVoxelSpacing((1.3556, 1.3556)) + + contract = CallableContract.from_callable(measure_object_size_shape) + _image, rows = CellProfilerFunctionContractExecutor().execute( + contract, contract.resolve_canonical_raw_callable(), source, + {"labels": value, "calculate_advanced": False, "calculate_zernikes": False}, + execution_mode=ImagePayloadExecutionMode.FULL_STACK, + ) + area = MeasureObjectSizeShapeModule.MeasurementFeature.AREA.value +> assert tuple(row[area] for row in rows) == (6.0, 12.0) +E assert (6.0, nan, na...nan, nan, ...) == (6.0, 12.0) +E +E At index 1 diff: nan != 12.0 +E Left contains 133 more items, first extra item: nan +E Use -v to get more diff + +tests/unit/test_saved_source_label_plane_domain.py:65: AssertionError +=============================== warnings summary =============================== +../../code/projects/openhcs/.venv/lib/python3.12/site-packages/_pytest/config/__init__.py:1441 + /home/ts/code/projects/openhcs/.venv/lib/python3.12/site-packages/_pytest/config/__init__.py:1441: PytestConfigWarning: Unknown config option: asyncio_default_fixture_loop_scope + + self._warn_or_fail_if_strict(f"Unknown config option: {key}\n") + +../../code/projects/openhcs/.venv/lib/python3.12/site-packages/_pytest/config/__init__.py:1441 + /home/ts/code/projects/openhcs/.venv/lib/python3.12/site-packages/_pytest/config/__init__.py:1441: PytestConfigWarning: Unknown config option: asyncio_mode + + self._warn_or_fail_if_strict(f"Unknown config option: {key}\n") + +-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html +- generated xml file: /home/ts/wt/openhcs-prior-measurement-role-projection-20261001/docs/validation/saved-label-plane-domain-419-20261002/geometry-focused-corrected.xml - +=========================== short test summary info ============================ +FAILED tests/unit/test_saved_source_label_plane_domain.py::test_original_artifact_admission_and_full_stack_shape_keep_2d_planes[runtime_slice] +FAILED tests/unit/test_saved_source_label_plane_domain.py::test_original_artifact_admission_and_full_stack_shape_keep_2d_planes[source_binding] +2 failed, 8 passed, 2 warnings in 20.53s +BOUNDED_SOURCE peak_aggregate_rss_kib=464172 elapsed_seconds=24.181 returncode=1 reason=None diff --git a/docs/validation/saved-label-plane-domain-419-20261002/geometry-focused-corrected.xml b/docs/validation/saved-label-plane-domain-419-20261002/geometry-focused-corrected.xml new file mode 100644 index 0000000000..cf1cbc8bf1 --- /dev/null +++ b/docs/validation/saved-label-plane-domain-419-20261002/geometry-focused-corrected.xml @@ -0,0 +1,75 @@ +axis = <RuntimePlaneAxis.RUNTIME_SLICE: 'runtime_slice'> + + @pytest.mark.parametrize("axis", tuple(RuntimePlaneAxis)) + def test_original_artifact_admission_and_full_stack_shape_keep_2d_planes(axis): + labels = np.zeros((2, 8, 9), dtype=np.int32) + labels[0, 1:3, 2:5] = 29 + labels[1, 2:5, 3:7] = 106 + source = _source(labels, axis=axis) + source_bytes = labels.tobytes() + spec = ArtifactSpec.input("saved_labels", ObjectLabelsArtifactType, parameter_name="labels") + value = RuntimeArtifactTypeStrategy.for_artifact_type(spec.artifact_type).runtime_input_value( + RuntimeArtifactInputRequest(spec=spec, value=source) + ) + assert value.domain.scope is ObjectLabelDomainScope.PLANE + assert value.plane_axis is axis + assert value.domain.declared_object_id_domains == ((29,), (106,)) + assert value.source_provenance.identity() == source.metadata.source_provenance.identity() + planes = value.measurement_planes() + assert tuple(plane.labels.shape for plane in planes) == ((8, 9), (8, 9)) + for index, plane in enumerate(planes): + np.testing.assert_array_equal(plane.labels, labels[index]) + assert plane.parent_image_source_voxel_spacing == SourceVoxelSpacing((1.3556, 1.3556)) + + contract = CallableContract.from_callable(measure_object_size_shape) + _image, rows = CellProfilerFunctionContractExecutor().execute( + contract, contract.resolve_canonical_raw_callable(), source, + {"labels": value, "calculate_advanced": False, "calculate_zernikes": False}, + execution_mode=ImagePayloadExecutionMode.FULL_STACK, + ) + area = MeasureObjectSizeShapeModule.MeasurementFeature.AREA.value +> assert tuple(row[area] for row in rows) == (6.0, 12.0) +E assert (6.0, nan, na...nan, nan, ...) == (6.0, 12.0) +E +E At index 1 diff: nan != 12.0 +E Left contains 133 more items, first extra item: nan +E Use -v to get more diff + +tests/unit/test_saved_source_label_plane_domain.py:65: AssertionErroraxis = <RuntimePlaneAxis.SOURCE_BINDING: 'source_binding'> + + @pytest.mark.parametrize("axis", tuple(RuntimePlaneAxis)) + def test_original_artifact_admission_and_full_stack_shape_keep_2d_planes(axis): + labels = np.zeros((2, 8, 9), dtype=np.int32) + labels[0, 1:3, 2:5] = 29 + labels[1, 2:5, 3:7] = 106 + source = _source(labels, axis=axis) + source_bytes = labels.tobytes() + spec = ArtifactSpec.input("saved_labels", ObjectLabelsArtifactType, parameter_name="labels") + value = RuntimeArtifactTypeStrategy.for_artifact_type(spec.artifact_type).runtime_input_value( + RuntimeArtifactInputRequest(spec=spec, value=source) + ) + assert value.domain.scope is ObjectLabelDomainScope.PLANE + assert value.plane_axis is axis + assert value.domain.declared_object_id_domains == ((29,), (106,)) + assert value.source_provenance.identity() == source.metadata.source_provenance.identity() + planes = value.measurement_planes() + assert tuple(plane.labels.shape for plane in planes) == ((8, 9), (8, 9)) + for index, plane in enumerate(planes): + np.testing.assert_array_equal(plane.labels, labels[index]) + assert plane.parent_image_source_voxel_spacing == SourceVoxelSpacing((1.3556, 1.3556)) + + contract = CallableContract.from_callable(measure_object_size_shape) + _image, rows = CellProfilerFunctionContractExecutor().execute( + contract, contract.resolve_canonical_raw_callable(), source, + {"labels": value, "calculate_advanced": False, "calculate_zernikes": False}, + execution_mode=ImagePayloadExecutionMode.FULL_STACK, + ) + area = MeasureObjectSizeShapeModule.MeasurementFeature.AREA.value +> assert tuple(row[area] for row in rows) == (6.0, 12.0) +E assert (6.0, nan, na...nan, nan, ...) == (6.0, 12.0) +E +E At index 1 diff: nan != 12.0 +E Left contains 133 more items, first extra item: nan +E Use -v to get more diff + +tests/unit/test_saved_source_label_plane_domain.py:65: AssertionError \ No newline at end of file diff --git a/docs/validation/saved-label-plane-domain-419-20261002/geometry-focused.log b/docs/validation/saved-label-plane-domain-419-20261002/geometry-focused.log new file mode 100644 index 0000000000..bd808eea17 --- /dev/null +++ b/docs/validation/saved-label-plane-domain-419-20261002/geometry-focused.log @@ -0,0 +1,79 @@ +Read-only native ABI: /home/ts/wt/openhcs-paired-raw-installed-parent-20261001/.venv/lib/python3.12/site-packages/openhcs/core/_tabular_native.abi3.so e1e0517b3706e6f6e8de126e8c3758c3a6bbf0ca024782b795fcb27d509f3e3e +Read-only native ABI: /home/ts/wt/openhcs-paired-raw-installed-parent-20261001/.venv/lib/python3.12/site-packages/openhcs/processing/backends/cellprofiler/_granularity_native.abi3.so 9f873070c3e136dd78109a55570852981e989c1d21e3452ce214bbaa753b7308 +Source owner: /home/ts/wt/openhcs-prior-measurement-role-projection-20261001/openhcs/core/function_patterns.py +Source owner: /home/ts/wt/openhcs-prior-measurement-role-projection-20261001/openhcs/core/pipeline/path_planner.py +Source owner: /home/ts/wt/openhcs-prior-measurement-role-projection-20261001/openhcs/core/steps/function_runtime.py +FF........ [100%] +=================================== FAILURES =================================== +_ test_original_artifact_admission_and_full_stack_shape_keep_2d_planes[runtime_slice] _ + +axis = + + @pytest.mark.parametrize("axis", tuple(RuntimePlaneAxis)) + def test_original_artifact_admission_and_full_stack_shape_keep_2d_planes(axis): + labels = np.zeros((2, 8, 9), dtype=np.int32) + labels[0, 1:3, 2:5] = 29 + labels[1, 2:5, 3:7] = 106 + source = _source(labels, axis=axis) + source_bytes = labels.tobytes() + spec = ArtifactSpec.input("saved_labels", ObjectLabelsArtifactType, parameter_name="labels") + value = RuntimeArtifactTypeStrategy.for_artifact_type(spec.artifact_type).runtime_input_value( + RuntimeArtifactInputRequest(spec=spec, value=source) + ) + assert value.domain.scope is ObjectLabelDomainScope.PLANE + assert value.plane_axis is axis + assert value.domain.declared_object_id_domains == ((29,), (106,)) +> assert value.source_provenance.identity == source.metadata.source_provenance.identity +E AssertionError: assert identity == identity +E + where identity = .identity +E + where = ObjectLabelSet(source_spatial_domain=SourceSpatialDomain(origin_yx=(0, 0), source_shape_yx=(8, 9), fill_value=0, value...rceVoxelSpacingUnit.MICROMETERS: 'micrometers'>), name='saved_labels', dimensions=(), source_image_name='saved_labels').source_provenance +E + and identity = .identity +E + where = ImagePayloadMetadata(source_voxel_spacing=SourceVoxelSpacing(values_zyx=(1.3556, 1.3556), unit=).source_provenance +E + where ImagePayloadMetadata(source_voxel_spacing=SourceVoxelSpacing(values_zyx=(1.3556, 1.3556), unit=) = ImageMetadataPayload(data=array([[[ 0, 0, 0, 0, 0, 0, 0, 0, 0],\n [ 0, 0, 29, 29, 29, 0...one, mask_defines_border=None, source_channel_axis=None, plane_axis=)).metadata + +tests/unit/test_saved_source_label_plane_domain.py:51: AssertionError +_ test_original_artifact_admission_and_full_stack_shape_keep_2d_planes[source_binding] _ + +axis = + + @pytest.mark.parametrize("axis", tuple(RuntimePlaneAxis)) + def test_original_artifact_admission_and_full_stack_shape_keep_2d_planes(axis): + labels = np.zeros((2, 8, 9), dtype=np.int32) + labels[0, 1:3, 2:5] = 29 + labels[1, 2:5, 3:7] = 106 + source = _source(labels, axis=axis) + source_bytes = labels.tobytes() + spec = ArtifactSpec.input("saved_labels", ObjectLabelsArtifactType, parameter_name="labels") + value = RuntimeArtifactTypeStrategy.for_artifact_type(spec.artifact_type).runtime_input_value( + RuntimeArtifactInputRequest(spec=spec, value=source) + ) + assert value.domain.scope is ObjectLabelDomainScope.PLANE + assert value.plane_axis is axis + assert value.domain.declared_object_id_domains == ((29,), (106,)) +> assert value.source_provenance.identity == source.metadata.source_provenance.identity +E AssertionError: assert identity == identity +E + where identity = .identity +E + where = ObjectLabelSet(source_spatial_domain=SourceSpatialDomain(origin_yx=(0, 0), source_shape_yx=(8, 9), fill_value=0, value...rceVoxelSpacingUnit.MICROMETERS: 'micrometers'>), name='saved_labels', dimensions=(), source_image_name='saved_labels').source_provenance +E + and identity = .identity +E + where = ImagePayloadMetadata(source_voxel_spacing=SourceVoxelSpacing(values_zyx=(1.3556, 1.3556), unit=).source_provenance +E + where ImagePayloadMetadata(source_voxel_spacing=SourceVoxelSpacing(values_zyx=(1.3556, 1.3556), unit=) = ImageMetadataPayload(data=array([[[ 0, 0, 0, 0, 0, 0, 0, 0, 0],\n [ 0, 0, 29, 29, 29, 0...e, mask_defines_border=None, source_channel_axis=None, plane_axis=)).metadata + +tests/unit/test_saved_source_label_plane_domain.py:51: AssertionError +=============================== warnings summary =============================== +../../code/projects/openhcs/.venv/lib/python3.12/site-packages/_pytest/config/__init__.py:1441 + /home/ts/code/projects/openhcs/.venv/lib/python3.12/site-packages/_pytest/config/__init__.py:1441: PytestConfigWarning: Unknown config option: asyncio_default_fixture_loop_scope + + self._warn_or_fail_if_strict(f"Unknown config option: {key}\n") + +../../code/projects/openhcs/.venv/lib/python3.12/site-packages/_pytest/config/__init__.py:1441 + /home/ts/code/projects/openhcs/.venv/lib/python3.12/site-packages/_pytest/config/__init__.py:1441: PytestConfigWarning: Unknown config option: asyncio_mode + + self._warn_or_fail_if_strict(f"Unknown config option: {key}\n") + +-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html +- generated xml file: /home/ts/wt/openhcs-prior-measurement-role-projection-20261001/docs/validation/saved-label-plane-domain-419-20261002/geometry-focused.xml - +=========================== short test summary info ============================ +FAILED tests/unit/test_saved_source_label_plane_domain.py::test_original_artifact_admission_and_full_stack_shape_keep_2d_planes[runtime_slice] +FAILED tests/unit/test_saved_source_label_plane_domain.py::test_original_artifact_admission_and_full_stack_shape_keep_2d_planes[source_binding] +2 failed, 8 passed, 2 warnings in 1.57s +BOUNDED_SOURCE peak_aggregate_rss_kib=322596 elapsed_seconds=4.871 returncode=1 reason=None diff --git a/docs/validation/saved-label-plane-domain-419-20261002/geometry-focused.xml b/docs/validation/saved-label-plane-domain-419-20261002/geometry-focused.xml new file mode 100644 index 0000000000..2c5220952d --- /dev/null +++ b/docs/validation/saved-label-plane-domain-419-20261002/geometry-focused.xml @@ -0,0 +1,49 @@ +axis = <RuntimePlaneAxis.RUNTIME_SLICE: 'runtime_slice'> + + @pytest.mark.parametrize("axis", tuple(RuntimePlaneAxis)) + def test_original_artifact_admission_and_full_stack_shape_keep_2d_planes(axis): + labels = np.zeros((2, 8, 9), dtype=np.int32) + labels[0, 1:3, 2:5] = 29 + labels[1, 2:5, 3:7] = 106 + source = _source(labels, axis=axis) + source_bytes = labels.tobytes() + spec = ArtifactSpec.input("saved_labels", ObjectLabelsArtifactType, parameter_name="labels") + value = RuntimeArtifactTypeStrategy.for_artifact_type(spec.artifact_type).runtime_input_value( + RuntimeArtifactInputRequest(spec=spec, value=source) + ) + assert value.domain.scope is ObjectLabelDomainScope.PLANE + assert value.plane_axis is axis + assert value.domain.declared_object_id_domains == ((29,), (106,)) +> assert value.source_provenance.identity == source.metadata.source_provenance.identity +E AssertionError: assert identity == identity +E + where identity = <openhcs.core.source_image_provenance.SourceImageProvenance object at 0x7fed6d50ce00>.identity +E + where <openhcs.core.source_image_provenance.SourceImageProvenance object at 0x7fed6d50ce00> = ObjectLabelSet(source_spatial_domain=SourceSpatialDomain(origin_yx=(0, 0), source_shape_yx=(8, 9), fill_value=0, value...rceVoxelSpacingUnit.MICROMETERS: 'micrometers'>), name='saved_labels', dimensions=(), source_image_name='saved_labels').source_provenance +E + and identity = <openhcs.core.source_image_provenance.SourceImageProvenance object at 0x7fed6d5ddf40>.identity +E + where <openhcs.core.source_image_provenance.SourceImageProvenance object at 0x7fed6d5ddf40> = ImagePayloadMetadata(source_voxel_spacing=SourceVoxelSpacing(values_zyx=(1.3556, 1.3556), unit=<SourceVoxelSpacingUnit...None, mask_defines_border=None, source_channel_axis=None, plane_axis=<RuntimePlaneAxis.RUNTIME_SLICE: 'runtime_slice'>).source_provenance +E + where ImagePayloadMetadata(source_voxel_spacing=SourceVoxelSpacing(values_zyx=(1.3556, 1.3556), unit=<SourceVoxelSpacingUnit...None, mask_defines_border=None, source_channel_axis=None, plane_axis=<RuntimePlaneAxis.RUNTIME_SLICE: 'runtime_slice'>) = ImageMetadataPayload(data=array([[[ 0, 0, 0, 0, 0, 0, 0, 0, 0],\n [ 0, 0, 29, 29, 29, 0...one, mask_defines_border=None, source_channel_axis=None, plane_axis=<RuntimePlaneAxis.RUNTIME_SLICE: 'runtime_slice'>)).metadata + +tests/unit/test_saved_source_label_plane_domain.py:51: AssertionErroraxis = <RuntimePlaneAxis.SOURCE_BINDING: 'source_binding'> + + @pytest.mark.parametrize("axis", tuple(RuntimePlaneAxis)) + def test_original_artifact_admission_and_full_stack_shape_keep_2d_planes(axis): + labels = np.zeros((2, 8, 9), dtype=np.int32) + labels[0, 1:3, 2:5] = 29 + labels[1, 2:5, 3:7] = 106 + source = _source(labels, axis=axis) + source_bytes = labels.tobytes() + spec = ArtifactSpec.input("saved_labels", ObjectLabelsArtifactType, parameter_name="labels") + value = RuntimeArtifactTypeStrategy.for_artifact_type(spec.artifact_type).runtime_input_value( + RuntimeArtifactInputRequest(spec=spec, value=source) + ) + assert value.domain.scope is ObjectLabelDomainScope.PLANE + assert value.plane_axis is axis + assert value.domain.declared_object_id_domains == ((29,), (106,)) +> assert value.source_provenance.identity == source.metadata.source_provenance.identity +E AssertionError: assert identity == identity +E + where identity = <openhcs.core.source_image_provenance.SourceImageProvenance object at 0x7fed6d73dcc0>.identity +E + where <openhcs.core.source_image_provenance.SourceImageProvenance object at 0x7fed6d73dcc0> = ObjectLabelSet(source_spatial_domain=SourceSpatialDomain(origin_yx=(0, 0), source_shape_yx=(8, 9), fill_value=0, value...rceVoxelSpacingUnit.MICROMETERS: 'micrometers'>), name='saved_labels', dimensions=(), source_image_name='saved_labels').source_provenance +E + and identity = <openhcs.core.source_image_provenance.SourceImageProvenance object at 0x7fed7c151900>.identity +E + where <openhcs.core.source_image_provenance.SourceImageProvenance object at 0x7fed7c151900> = ImagePayloadMetadata(source_voxel_spacing=SourceVoxelSpacing(values_zyx=(1.3556, 1.3556), unit=<SourceVoxelSpacingUnit...ne, mask_defines_border=None, source_channel_axis=None, plane_axis=<RuntimePlaneAxis.SOURCE_BINDING: 'source_binding'>).source_provenance +E + where ImagePayloadMetadata(source_voxel_spacing=SourceVoxelSpacing(values_zyx=(1.3556, 1.3556), unit=<SourceVoxelSpacingUnit...ne, mask_defines_border=None, source_channel_axis=None, plane_axis=<RuntimePlaneAxis.SOURCE_BINDING: 'source_binding'>) = ImageMetadataPayload(data=array([[[ 0, 0, 0, 0, 0, 0, 0, 0, 0],\n [ 0, 0, 29, 29, 29, 0...e, mask_defines_border=None, source_channel_axis=None, plane_axis=<RuntimePlaneAxis.SOURCE_BINDING: 'source_binding'>)).metadata + +tests/unit/test_saved_source_label_plane_domain.py:51: AssertionError \ No newline at end of file diff --git a/docs/validation/saved-label-plane-domain-419-20261002/metadata-owner-proposal.patch b/docs/validation/saved-label-plane-domain-419-20261002/metadata-owner-proposal.patch new file mode 100644 index 0000000000..a58137aae0 --- /dev/null +++ b/docs/validation/saved-label-plane-domain-419-20261002/metadata-owner-proposal.patch @@ -0,0 +1,38 @@ +diff --git a/openhcs/core/runtime_image_values.py b/openhcs/core/runtime_image_values.py +--- a/openhcs/core/runtime_image_values.py ++++ b/openhcs/core/runtime_image_values.py +@@ -137,6 +137,16 @@ class ImagePayloadMetadata( + if member.metadata.get(ViewerWireField.IMAGE_METADATA, False) + ) + ++ def preserved_plane_projection(self) -> RuntimePlaneAxisValueProjection | None: ++ """Retain this payload's exact declared non-spatial leading axis.""" ++ if self.plane_axis is None: ++ return None ++ return RuntimePlaneAxisValueProjection.preserve( ++ axis=self.plane_axis, ++ axis_size=self.source_provenance.source_plane_count, ++ source_aliases=self.source_image_names, ++ ) ++ + def singleton_plane_projection(self) -> RuntimePlaneAxisValueProjection | None: + """Select a declared leading axis only with one exact runtime source plane.""" + plane_count = self.source_provenance.source_plane_count +diff --git a/openhcs/core/runtime_object_label_building.py b/openhcs/core/runtime_object_label_building.py +--- a/openhcs/core/runtime_object_label_building.py ++++ b/openhcs/core/runtime_object_label_building.py +@@ -130,12 +130,8 @@ class SourceImageObjectLabelBuildRequest: + ) + projection = self.plane_projection + metadata = self.metadata +- if metadata.plane_axis is not None: +- declared_projection = RuntimePlaneAxisValueProjection.preserve( +- axis=metadata.plane_axis, +- axis_size=metadata.source_provenance.source_plane_count, +- source_aliases=metadata.source_image_names, +- ) ++ declared_projection = metadata.preserved_plane_projection() ++ if declared_projection is not None: + if projection is None: + projection = declared_projection + elif ( diff --git a/docs/validation/saved-label-plane-domain-419-20261002/original-red.log b/docs/validation/saved-label-plane-domain-419-20261002/original-red.log new file mode 100644 index 0000000000..f0a4d63621 --- /dev/null +++ b/docs/validation/saved-label-plane-domain-419-20261002/original-red.log @@ -0,0 +1,151 @@ +Read-only native ABI: /home/ts/wt/openhcs-paired-raw-installed-parent-20261001/.venv/lib/python3.12/site-packages/openhcs/core/_tabular_native.abi3.so e1e0517b3706e6f6e8de126e8c3758c3a6bbf0ca024782b795fcb27d509f3e3e +Read-only native ABI: /home/ts/wt/openhcs-paired-raw-installed-parent-20261001/.venv/lib/python3.12/site-packages/openhcs/processing/backends/cellprofiler/_granularity_native.abi3.so 9f873070c3e136dd78109a55570852981e989c1d21e3452ce214bbaa753b7308 +Source owner: /home/ts/wt/openhcs-prior-measurement-role-projection-20261001/openhcs/core/function_patterns.py +Source owner: /home/ts/wt/openhcs-prior-measurement-role-projection-20261001/openhcs/core/pipeline/path_planner.py +Source owner: /home/ts/wt/openhcs-prior-measurement-role-projection-20261001/openhcs/core/steps/function_runtime.py +FFF.FFFFFF [100%] +=================================== FAILURES =================================== +_ test_original_artifact_admission_and_full_stack_shape_keep_2d_planes[runtime_slice] _ + +axis = + + @pytest.mark.parametrize("axis", tuple(RuntimePlaneAxis)) + def test_original_artifact_admission_and_full_stack_shape_keep_2d_planes(axis): + labels = np.zeros((2, 8, 9), dtype=np.int32) + labels[0, 1:3, 2:5] = 29 + labels[1, 2:5, 3:7] = 106 + source = _source(labels, axis=axis) + source_bytes = labels.tobytes() + spec = ArtifactSpec.input("saved_labels", ObjectLabelsArtifactType, parameter_name="labels") + value = RuntimeArtifactTypeStrategy.for_artifact_type(spec.artifact_type).runtime_input_value( + RuntimeArtifactInputRequest(spec=spec, value=source) + ) +> assert value.domain.scope is ObjectLabelDomainScope.PLANE +E AssertionError: assert is +E + where = ObjectLabelDomain(declared_object_count=None, declared_object_ids=(29, 106), declared_object_id_domains=(), scope=).scope +E + where ObjectLabelDomain(declared_object_count=None, declared_object_ids=(29, 106), declared_object_id_domains=(), scope=) = ObjectLabelSet(source_spatial_domain=SourceSpatialDomain(origin_yx=(0, 0), source_shape_yx=(8, 9), fill_value=0, value...rceVoxelSpacingUnit.MICROMETERS: 'micrometers'>), name='saved_labels', dimensions=(), source_image_name='saved_labels').domain +E + and = ObjectLabelDomainScope.PLANE + +tests/unit/test_saved_source_label_plane_domain.py:48: AssertionError +_ test_original_artifact_admission_and_full_stack_shape_keep_2d_planes[source_binding] _ + +axis = + + @pytest.mark.parametrize("axis", tuple(RuntimePlaneAxis)) + def test_original_artifact_admission_and_full_stack_shape_keep_2d_planes(axis): + labels = np.zeros((2, 8, 9), dtype=np.int32) + labels[0, 1:3, 2:5] = 29 + labels[1, 2:5, 3:7] = 106 + source = _source(labels, axis=axis) + source_bytes = labels.tobytes() + spec = ArtifactSpec.input("saved_labels", ObjectLabelsArtifactType, parameter_name="labels") + value = RuntimeArtifactTypeStrategy.for_artifact_type(spec.artifact_type).runtime_input_value( + RuntimeArtifactInputRequest(spec=spec, value=source) + ) +> assert value.domain.scope is ObjectLabelDomainScope.PLANE +E AssertionError: assert is +E + where = ObjectLabelDomain(declared_object_count=None, declared_object_ids=(29, 106), declared_object_id_domains=(), scope=).scope +E + where ObjectLabelDomain(declared_object_count=None, declared_object_ids=(29, 106), declared_object_id_domains=(), scope=) = ObjectLabelSet(source_spatial_domain=SourceSpatialDomain(origin_yx=(0, 0), source_shape_yx=(8, 9), fill_value=0, value...rceVoxelSpacingUnit.MICROMETERS: 'micrometers'>), name='saved_labels', dimensions=(), source_image_name='saved_labels').domain +E + and = ObjectLabelDomainScope.PLANE + +tests/unit/test_saved_source_label_plane_domain.py:48: AssertionError +____________ test_singleton_runtime_slice_is_not_a_physical_volume _____________ + + def test_singleton_runtime_slice_is_not_a_physical_volume(): + labels = np.zeros((1, 6, 7), dtype=np.int32) + labels[0, 1:4, 2:5] = 61 + value = SourceImageObjectLabelBuildRequest(image=_source(labels), labels=labels).payload() +> assert value.domain.declared_object_id_domains == ((61,),) +E assert () == ((61,),) +E +E Right contains one more item: (61,) +E Use -v to get more diff + +tests/unit/test_saved_source_label_plane_domain.py:74: AssertionError +_______ test_declared_axis_rejects_missing_or_conflicting_cardinality[0] _______ + +plane_count = 0 + + @pytest.mark.parametrize("plane_count", (0, 1, 3)) + def test_declared_axis_rejects_missing_or_conflicting_cardinality(plane_count): + labels = np.ones((2, 6, 7), dtype=np.int32) +> with pytest.raises(ValueError): +E Failed: DID NOT RAISE + +tests/unit/test_saved_source_label_plane_domain.py:95: Failed +_______ test_declared_axis_rejects_missing_or_conflicting_cardinality[1] _______ + +plane_count = 1 + + @pytest.mark.parametrize("plane_count", (0, 1, 3)) + def test_declared_axis_rejects_missing_or_conflicting_cardinality(plane_count): + labels = np.ones((2, 6, 7), dtype=np.int32) +> with pytest.raises(ValueError): +E Failed: DID NOT RAISE + +tests/unit/test_saved_source_label_plane_domain.py:95: Failed +_______ test_declared_axis_rejects_missing_or_conflicting_cardinality[3] _______ + +plane_count = 3 + + @pytest.mark.parametrize("plane_count", (0, 1, 3)) + def test_declared_axis_rejects_missing_or_conflicting_cardinality(plane_count): + labels = np.ones((2, 6, 7), dtype=np.int32) +> with pytest.raises(ValueError): +E Failed: DID NOT RAISE + +tests/unit/test_saved_source_label_plane_domain.py:95: Failed +__ test_declared_axis_rejects_payload_wide_ids_and_mismatched_label_geometry ___ + + def test_declared_axis_rejects_payload_wide_ids_and_mismatched_label_geometry(): + labels = np.ones((2, 6, 7), dtype=np.int32) + source = _source(labels) +> with pytest.raises(ValueError, match="per-plane domains"): +E Failed: DID NOT RAISE + +tests/unit/test_saved_source_label_plane_domain.py:102: Failed +___ test_explicit_projection_conflicting_with_source_declaration_is_rejected ___ + + def test_explicit_projection_conflicting_with_source_declaration_is_rejected(): + labels = np.ones((2, 6, 7), dtype=np.int32) +> with pytest.raises(ValueError, match="conflicts"): +E Failed: DID NOT RAISE + +tests/unit/test_saved_source_label_plane_domain.py:110: Failed +__ test_new_calibrated_leaf_executes_cooperative_admission_and_plane_building __ + + def test_new_calibrated_leaf_executes_cooperative_admission_and_plane_building(): + labels = np.ones((2, 6, 7), dtype=np.int32) + value = CalibratedSavedLabels(image=_source(labels), labels=labels).payload() +> assert value.domain.scope is ObjectLabelDomainScope.PLANE +E AssertionError: assert is +E + where = ObjectLabelDomain(declared_object_count=None, declared_object_ids=(1,), declared_object_id_domains=(), scope=).scope +E + where ObjectLabelDomain(declared_object_count=None, declared_object_ids=(1,), declared_object_id_domains=(), scope=) = ObjectLabelPayload(source_spatial_domain=SourceSpatialDomain(origin_yx=(0, 0), source_shape_yx=(6, 7), fill_value=0, v...oxel_spacing=SourceVoxelSpacing(values_zyx=(1.3556, 1.3556), unit=)).domain +E + and = ObjectLabelDomainScope.PLANE + +tests/unit/test_saved_source_label_plane_domain.py:132: AssertionError +=============================== warnings summary =============================== +../../code/projects/openhcs/.venv/lib/python3.12/site-packages/_pytest/config/__init__.py:1441 + /home/ts/code/projects/openhcs/.venv/lib/python3.12/site-packages/_pytest/config/__init__.py:1441: PytestConfigWarning: Unknown config option: asyncio_default_fixture_loop_scope + + self._warn_or_fail_if_strict(f"Unknown config option: {key}\n") + +../../code/projects/openhcs/.venv/lib/python3.12/site-packages/_pytest/config/__init__.py:1441 + /home/ts/code/projects/openhcs/.venv/lib/python3.12/site-packages/_pytest/config/__init__.py:1441: PytestConfigWarning: Unknown config option: asyncio_mode + + self._warn_or_fail_if_strict(f"Unknown config option: {key}\n") + +-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html +- generated xml file: /home/ts/wt/openhcs-prior-measurement-role-projection-20261001/docs/validation/saved-label-plane-domain-419-20261002/original-red.xml - +=========================== short test summary info ============================ +FAILED tests/unit/test_saved_source_label_plane_domain.py::test_original_artifact_admission_and_full_stack_shape_keep_2d_planes[runtime_slice] +FAILED tests/unit/test_saved_source_label_plane_domain.py::test_original_artifact_admission_and_full_stack_shape_keep_2d_planes[source_binding] +FAILED tests/unit/test_saved_source_label_plane_domain.py::test_singleton_runtime_slice_is_not_a_physical_volume +FAILED tests/unit/test_saved_source_label_plane_domain.py::test_declared_axis_rejects_missing_or_conflicting_cardinality[0] +FAILED tests/unit/test_saved_source_label_plane_domain.py::test_declared_axis_rejects_missing_or_conflicting_cardinality[1] +FAILED tests/unit/test_saved_source_label_plane_domain.py::test_declared_axis_rejects_missing_or_conflicting_cardinality[3] +FAILED tests/unit/test_saved_source_label_plane_domain.py::test_declared_axis_rejects_payload_wide_ids_and_mismatched_label_geometry +FAILED tests/unit/test_saved_source_label_plane_domain.py::test_explicit_projection_conflicting_with_source_declaration_is_rejected +FAILED tests/unit/test_saved_source_label_plane_domain.py::test_new_calibrated_leaf_executes_cooperative_admission_and_plane_building +9 failed, 1 passed, 2 warnings in 1.84s +BOUNDED_SOURCE peak_aggregate_rss_kib=329084 elapsed_seconds=5.371 returncode=1 reason=None diff --git a/docs/validation/saved-label-plane-domain-419-20261002/original-red.xml b/docs/validation/saved-label-plane-domain-419-20261002/original-red.xml new file mode 100644 index 0000000000..0ea07a91ad --- /dev/null +++ b/docs/validation/saved-label-plane-domain-419-20261002/original-red.xml @@ -0,0 +1,93 @@ +axis = <RuntimePlaneAxis.RUNTIME_SLICE: 'runtime_slice'> + + @pytest.mark.parametrize("axis", tuple(RuntimePlaneAxis)) + def test_original_artifact_admission_and_full_stack_shape_keep_2d_planes(axis): + labels = np.zeros((2, 8, 9), dtype=np.int32) + labels[0, 1:3, 2:5] = 29 + labels[1, 2:5, 3:7] = 106 + source = _source(labels, axis=axis) + source_bytes = labels.tobytes() + spec = ArtifactSpec.input("saved_labels", ObjectLabelsArtifactType, parameter_name="labels") + value = RuntimeArtifactTypeStrategy.for_artifact_type(spec.artifact_type).runtime_input_value( + RuntimeArtifactInputRequest(spec=spec, value=source) + ) +> assert value.domain.scope is ObjectLabelDomainScope.PLANE +E AssertionError: assert <ObjectLabelDomainScope.PAYLOAD: 'payload'> is <ObjectLabelDomainScope.PLANE: 'plane'> +E + where <ObjectLabelDomainScope.PAYLOAD: 'payload'> = ObjectLabelDomain(declared_object_count=None, declared_object_ids=(29, 106), declared_object_id_domains=(), scope=<ObjectLabelDomainScope.PAYLOAD: 'payload'>).scope +E + where ObjectLabelDomain(declared_object_count=None, declared_object_ids=(29, 106), declared_object_id_domains=(), scope=<ObjectLabelDomainScope.PAYLOAD: 'payload'>) = ObjectLabelSet(source_spatial_domain=SourceSpatialDomain(origin_yx=(0, 0), source_shape_yx=(8, 9), fill_value=0, value...rceVoxelSpacingUnit.MICROMETERS: 'micrometers'>), name='saved_labels', dimensions=(), source_image_name='saved_labels').domain +E + and <ObjectLabelDomainScope.PLANE: 'plane'> = ObjectLabelDomainScope.PLANE + +tests/unit/test_saved_source_label_plane_domain.py:48: AssertionErroraxis = <RuntimePlaneAxis.SOURCE_BINDING: 'source_binding'> + + @pytest.mark.parametrize("axis", tuple(RuntimePlaneAxis)) + def test_original_artifact_admission_and_full_stack_shape_keep_2d_planes(axis): + labels = np.zeros((2, 8, 9), dtype=np.int32) + labels[0, 1:3, 2:5] = 29 + labels[1, 2:5, 3:7] = 106 + source = _source(labels, axis=axis) + source_bytes = labels.tobytes() + spec = ArtifactSpec.input("saved_labels", ObjectLabelsArtifactType, parameter_name="labels") + value = RuntimeArtifactTypeStrategy.for_artifact_type(spec.artifact_type).runtime_input_value( + RuntimeArtifactInputRequest(spec=spec, value=source) + ) +> assert value.domain.scope is ObjectLabelDomainScope.PLANE +E AssertionError: assert <ObjectLabelDomainScope.PAYLOAD: 'payload'> is <ObjectLabelDomainScope.PLANE: 'plane'> +E + where <ObjectLabelDomainScope.PAYLOAD: 'payload'> = ObjectLabelDomain(declared_object_count=None, declared_object_ids=(29, 106), declared_object_id_domains=(), scope=<ObjectLabelDomainScope.PAYLOAD: 'payload'>).scope +E + where ObjectLabelDomain(declared_object_count=None, declared_object_ids=(29, 106), declared_object_id_domains=(), scope=<ObjectLabelDomainScope.PAYLOAD: 'payload'>) = ObjectLabelSet(source_spatial_domain=SourceSpatialDomain(origin_yx=(0, 0), source_shape_yx=(8, 9), fill_value=0, value...rceVoxelSpacingUnit.MICROMETERS: 'micrometers'>), name='saved_labels', dimensions=(), source_image_name='saved_labels').domain +E + and <ObjectLabelDomainScope.PLANE: 'plane'> = ObjectLabelDomainScope.PLANE + +tests/unit/test_saved_source_label_plane_domain.py:48: AssertionErrordef test_singleton_runtime_slice_is_not_a_physical_volume(): + labels = np.zeros((1, 6, 7), dtype=np.int32) + labels[0, 1:4, 2:5] = 61 + value = SourceImageObjectLabelBuildRequest(image=_source(labels), labels=labels).payload() +> assert value.domain.declared_object_id_domains == ((61,),) +E assert () == ((61,),) +E +E Right contains one more item: (61,) +E Use -v to get more diff + +tests/unit/test_saved_source_label_plane_domain.py:74: AssertionErrorplane_count = 0 + + @pytest.mark.parametrize("plane_count", (0, 1, 3)) + def test_declared_axis_rejects_missing_or_conflicting_cardinality(plane_count): + labels = np.ones((2, 6, 7), dtype=np.int32) +> with pytest.raises(ValueError): +E Failed: DID NOT RAISE <class 'ValueError'> + +tests/unit/test_saved_source_label_plane_domain.py:95: Failedplane_count = 1 + + @pytest.mark.parametrize("plane_count", (0, 1, 3)) + def test_declared_axis_rejects_missing_or_conflicting_cardinality(plane_count): + labels = np.ones((2, 6, 7), dtype=np.int32) +> with pytest.raises(ValueError): +E Failed: DID NOT RAISE <class 'ValueError'> + +tests/unit/test_saved_source_label_plane_domain.py:95: Failedplane_count = 3 + + @pytest.mark.parametrize("plane_count", (0, 1, 3)) + def test_declared_axis_rejects_missing_or_conflicting_cardinality(plane_count): + labels = np.ones((2, 6, 7), dtype=np.int32) +> with pytest.raises(ValueError): +E Failed: DID NOT RAISE <class 'ValueError'> + +tests/unit/test_saved_source_label_plane_domain.py:95: Faileddef test_declared_axis_rejects_payload_wide_ids_and_mismatched_label_geometry(): + labels = np.ones((2, 6, 7), dtype=np.int32) + source = _source(labels) +> with pytest.raises(ValueError, match="per-plane domains"): +E Failed: DID NOT RAISE <class 'ValueError'> + +tests/unit/test_saved_source_label_plane_domain.py:102: Faileddef test_explicit_projection_conflicting_with_source_declaration_is_rejected(): + labels = np.ones((2, 6, 7), dtype=np.int32) +> with pytest.raises(ValueError, match="conflicts"): +E Failed: DID NOT RAISE <class 'ValueError'> + +tests/unit/test_saved_source_label_plane_domain.py:110: Faileddef test_new_calibrated_leaf_executes_cooperative_admission_and_plane_building(): + labels = np.ones((2, 6, 7), dtype=np.int32) + value = CalibratedSavedLabels(image=_source(labels), labels=labels).payload() +> assert value.domain.scope is ObjectLabelDomainScope.PLANE +E AssertionError: assert <ObjectLabelDomainScope.PAYLOAD: 'payload'> is <ObjectLabelDomainScope.PLANE: 'plane'> +E + where <ObjectLabelDomainScope.PAYLOAD: 'payload'> = ObjectLabelDomain(declared_object_count=None, declared_object_ids=(1,), declared_object_id_domains=(), scope=<ObjectLabelDomainScope.PAYLOAD: 'payload'>).scope +E + where ObjectLabelDomain(declared_object_count=None, declared_object_ids=(1,), declared_object_id_domains=(), scope=<ObjectLabelDomainScope.PAYLOAD: 'payload'>) = ObjectLabelPayload(source_spatial_domain=SourceSpatialDomain(origin_yx=(0, 0), source_shape_yx=(6, 7), fill_value=0, v...oxel_spacing=SourceVoxelSpacing(values_zyx=(1.3556, 1.3556), unit=<SourceVoxelSpacingUnit.MICROMETERS: 'micrometers'>)).domain +E + and <ObjectLabelDomainScope.PLANE: 'plane'> = ObjectLabelDomainScope.PLANE + +tests/unit/test_saved_source_label_plane_domain.py:132: AssertionError \ No newline at end of file diff --git a/docs/validation/saved-label-plane-domain-419-20261002/projection-owner-controls.log b/docs/validation/saved-label-plane-domain-419-20261002/projection-owner-controls.log new file mode 100644 index 0000000000..94c17b5c28 --- /dev/null +++ b/docs/validation/saved-label-plane-domain-419-20261002/projection-owner-controls.log @@ -0,0 +1,23 @@ +Read-only native ABI: /home/ts/wt/openhcs-paired-raw-installed-parent-20261001/.venv/lib/python3.12/site-packages/openhcs/core/_tabular_native.abi3.so e1e0517b3706e6f6e8de126e8c3758c3a6bbf0ca024782b795fcb27d509f3e3e +Read-only native ABI: /home/ts/wt/openhcs-paired-raw-installed-parent-20261001/.venv/lib/python3.12/site-packages/openhcs/processing/backends/cellprofiler/_granularity_native.abi3.so 9f873070c3e136dd78109a55570852981e989c1d21e3452ce214bbaa753b7308 +Source owner: /home/ts/wt/openhcs-prior-measurement-role-projection-20261001/openhcs/core/function_patterns.py +Source owner: /home/ts/wt/openhcs-prior-measurement-role-projection-20261001/openhcs/core/pipeline/path_planner.py +Source owner: /home/ts/wt/openhcs-prior-measurement-role-projection-20261001/openhcs/core/steps/function_runtime.py +........................................................................ [ 34%] +........................................................................ [ 68%] +................................................................. [100%] +=============================== warnings summary =============================== +../../code/projects/openhcs/.venv/lib/python3.12/site-packages/_pytest/config/__init__.py:1441 + /home/ts/code/projects/openhcs/.venv/lib/python3.12/site-packages/_pytest/config/__init__.py:1441: PytestConfigWarning: Unknown config option: asyncio_default_fixture_loop_scope + + self._warn_or_fail_if_strict(f"Unknown config option: {key}\n") + +../../code/projects/openhcs/.venv/lib/python3.12/site-packages/_pytest/config/__init__.py:1441 + /home/ts/code/projects/openhcs/.venv/lib/python3.12/site-packages/_pytest/config/__init__.py:1441: PytestConfigWarning: Unknown config option: asyncio_mode + + self._warn_or_fail_if_strict(f"Unknown config option: {key}\n") + +-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html +- generated xml file: /home/ts/wt/openhcs-prior-measurement-role-projection-20261001/docs/validation/saved-label-plane-domain-419-20261002/projection-owner-controls.xml - +209 passed, 2 warnings in 5.04s +BOUNDED_SOURCE peak_aggregate_rss_kib=416796 elapsed_seconds=8.771 returncode=0 reason=None diff --git a/docs/validation/saved-label-plane-domain-419-20261002/projection-owner-controls.xml b/docs/validation/saved-label-plane-domain-419-20261002/projection-owner-controls.xml new file mode 100644 index 0000000000..edffba8416 --- /dev/null +++ b/docs/validation/saved-label-plane-domain-419-20261002/projection-owner-controls.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/validation/saved-label-plane-domain-419-20261002/r0-final-production.log.gz b/docs/validation/saved-label-plane-domain-419-20261002/r0-final-production.log.gz new file mode 100644 index 0000000000..0afc257ae9 Binary files /dev/null and b/docs/validation/saved-label-plane-domain-419-20261002/r0-final-production.log.gz differ diff --git a/docs/validation/saved-label-plane-domain-419-20261002/r0-original-pin.log.gz b/docs/validation/saved-label-plane-domain-419-20261002/r0-original-pin.log.gz new file mode 100644 index 0000000000..e02043a93a Binary files /dev/null and b/docs/validation/saved-label-plane-domain-419-20261002/r0-original-pin.log.gz differ diff --git a/docs/validation/saved-label-plane-domain-419-20261002/r0-unapplied-metadata-proposal.log b/docs/validation/saved-label-plane-domain-419-20261002/r0-unapplied-metadata-proposal.log new file mode 100644 index 0000000000..53c0e7f55a --- /dev/null +++ b/docs/validation/saved-label-plane-domain-419-20261002/r0-unapplied-metadata-proposal.log @@ -0,0 +1,27 @@ +Original R0 source: /home/ts/.agent-comms@3b03785f45df2ef5dc62ba6aed99294192ecbb01; dependency backing: /home/ts/wt/basicpy-live-candidate-20260930/.venv/lib/python3.12/site-packages +error: aa0d5552a2761f5a7ee07190f27064563ecb5a98^{commit}: expected commit type, but the object dereferences to tree type +fatal: Needed a single revision +Traceback (most recent call last): + File "/home/ts/wt/openhcs-prior-measurement-role-projection-20261001/validation/run_pinned_r0_419.py", line 58, in + raise SystemExit(main()) + ~~~~^^ + File "/home/ts/.agent-comms@3b03785f45df2ef5dc62ba6aed99294192ecbb01/src/agent_comms/debt_ratchet.py", line 525, in main + result = compare(Path.cwd(), args.base, args.head, args.root) + File "/home/ts/.agent-comms@3b03785f45df2ef5dc62ba6aed99294192ecbb01/src/agent_comms/debt_ratchet.py", line 502, in compare + base, head = revision(repo, base), revision(repo, head) + ~~~~~~~~^^^^^^^^^^^^ + File "/home/ts/.agent-comms@3b03785f45df2ef5dc62ba6aed99294192ecbb01/src/agent_comms/debt_ratchet.py", line 467, in revision + git(repo, "rev-parse", "--verify", "--end-of-options", f"{ref}^{{commit}}").decode().strip() + ~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/home/ts/.agent-comms@3b03785f45df2ef5dc62ba6aed99294192ecbb01/src/agent_comms/debt_ratchet.py", line 462, in git + return subprocess.check_output(["git", "-C", str(repo), *args], timeout=20) + ~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/home/ts/.local/share/uv/python/cpython-3.14.2-linux-x86_64-gnu/lib/python3.14/subprocess.py", line 472, in check_output + return run(*popenargs, stdout=PIPE, timeout=timeout, check=True, + ~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + **kwargs).stdout + ^^^^^^^^^ + File "/home/ts/.local/share/uv/python/cpython-3.14.2-linux-x86_64-gnu/lib/python3.14/subprocess.py", line 577, in run + raise CalledProcessError(retcode, process.args, + output=stdout, stderr=stderr) +subprocess.CalledProcessError: Command '['git', '-C', '/home/ts/wt/openhcs-prior-measurement-role-projection-20261001', 'rev-parse', '--verify', '--end-of-options', 'aa0d5552a2761f5a7ee07190f27064563ecb5a98^{commit}']' returned non-zero exit status 128. diff --git a/docs/validation/saved-label-plane-domain-419-20261002/r0-unapplied-proposal-commit.log.gz b/docs/validation/saved-label-plane-domain-419-20261002/r0-unapplied-proposal-commit.log.gz new file mode 100644 index 0000000000..16cf8a7b0e Binary files /dev/null and b/docs/validation/saved-label-plane-domain-419-20261002/r0-unapplied-proposal-commit.log.gz differ diff --git a/openhcs/core/runtime_object_label_building.py b/openhcs/core/runtime_object_label_building.py index 31f6da0788..799dfd5202 100644 --- a/openhcs/core/runtime_object_label_building.py +++ b/openhcs/core/runtime_object_label_building.py @@ -128,7 +128,23 @@ def plane_semantics(self) -> RuntimePlaneAxisValueProjection | None: "Source-image object-label domain_scope must be payload, plane, " f"or None; got {self.domain_scope!r}." ) - if self.plane_projection is None: + projection = self.plane_projection + metadata = self.metadata + declared_projection = RuntimePlaneAxisValueProjection.from_source_declaration( + metadata.plane_axis, metadata.source_provenance, + ) + if declared_projection is not None: + if projection is None: + projection = declared_projection + elif ( + projection.axis is not declared_projection.axis + or projection.axis_size != declared_projection.axis_size + ): + raise ValueError( + "Object-label plane projection conflicts with the source-image " + "axis declaration." + ) + if projection is None: if self.domain_scope is ObjectLabelDomainScope.PLANE: raise ValueError( "Plane-scoped object-label output requires an exact plane " @@ -136,15 +152,15 @@ def plane_semantics(self) -> RuntimePlaneAxisValueProjection | None: ) return None label_array = np.asarray(self.labels) - self.plane_projection.validate_shape( + projection.validate_shape( label_array.shape, value_name="Source-image object labels", ) - self.plane_projection.validate_shape( + projection.validate_shape( runtime_image_values.image_payload_geometry(self.image).shape, value_name="Object-label source image", ) - source_shape_yx = self.metadata.spatial_shape_yx(self.image) + source_shape_yx = metadata.spatial_shape_yx(self.image) if source_shape_yx is None: raise ValueError( "Declared source-image plane axis requires a source spatial domain." @@ -154,4 +170,4 @@ def plane_semantics(self) -> RuntimePlaneAxisValueProjection | None: "Object-label spatial shape must match the declared source-image " f"domain: {tuple(label_array.shape[-2:])!r} != {tuple(source_shape_yx)!r}." ) - return self.plane_projection + return projection diff --git a/openhcs/core/runtime_plane_projection.py b/openhcs/core/runtime_plane_projection.py index 79cec16cf2..fe1bf18bc0 100644 --- a/openhcs/core/runtime_plane_projection.py +++ b/openhcs/core/runtime_plane_projection.py @@ -10,6 +10,10 @@ from collections.abc import Sequence from typing import ClassVar from typing import Self +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from openhcs.core.source_image_provenance import SourceImageProvenance class RuntimeSliceProjectableValue(ABC): @@ -246,6 +250,26 @@ def __post_init__(self) -> None: object.__setattr__(self, "axis_size", axis_size) object.__setattr__(self, "plane_index", plane_index) + @classmethod + def from_source_declaration( + cls, + axis: RuntimePlaneAxis | None, + source: "SourceImageProvenance", + ) -> "RuntimePlaneAxisValueProjection | None": + """Construct the retained axis declared by an exact source-image value. + + A missing axis declares no plane projection, even when provenance has + multiple contributors. Cardinality and aliases come from that original + source declaration; array rank never supplies spatial meaning. + """ + if axis is None: + return None + return cls.preserve( + axis=axis, + axis_size=source.source_plane_count, + source_aliases=source.source_image_names, + ) + @classmethod def from_projector( cls, diff --git a/tests/unit/test_saved_source_label_plane_domain.py b/tests/unit/test_saved_source_label_plane_domain.py new file mode 100644 index 0000000000..d20db47931 --- /dev/null +++ b/tests/unit/test_saved_source_label_plane_domain.py @@ -0,0 +1,180 @@ +"""Saved label admission retains declared runtime axes, never guessed Z axes.""" + +from __future__ import annotations + +import numpy as np +import pytest + +from openhcs.core.aligned_image_payload import ImagePayloadExecutionMode +from openhcs.core.artifacts import ArtifactSpec, ObjectLabelsArtifactType +from openhcs.core.callable_contract import CallableContract +from openhcs.core.runtime_image_values import ImagePayloadMetadata +from openhcs.core.runtime_object_label_building import SourceImageObjectLabelBuildRequest +from openhcs.core.runtime_object_label_domains import ObjectLabelDomainScope +from openhcs.core.runtime_plane_projection import RuntimePlaneAxis, RuntimePlaneAxisValueProjection +from openhcs.core.source_image_provenance import SourceImageProvenancePlanes +from openhcs.core.source_metadata import SourceVoxelSpacing +from openhcs.interop.cellprofiler.runtime.artifact_binding import ( + RuntimeArtifactInputRequest, RuntimeArtifactTypeStrategy, +) +from openhcs.interop.cellprofiler.runtime.function_contract_execution import CellProfilerFunctionContractExecutor +from openhcs.processing.backends.cellprofiler.shape import MeasureObjectSizeShapeModule, measure_object_size_shape + + +def _source(labels, *, axis=RuntimePlaneAxis.RUNTIME_SLICE, plane_count=None, spacing=(1.3556, 1.3556)): + count = labels.shape[0] if plane_count is None else plane_count + return ImagePayloadMetadata( + plane_axis=axis, + source_image_names=("saved_labels",) * count, + source_image_provenance_planes=SourceImageProvenancePlanes.from_components( + paths=tuple(f"/synthetic/A01_s001_w{index + 1}_labels.tif" for index in range(count)), + component_metadata=tuple({"well": "A01", "site": "1", "channel": str(index + 1)} for index in range(count)), + ), + source_voxel_spacing=SourceVoxelSpacing(spacing), + ).payload_with(labels, None) + + +@pytest.mark.parametrize("axis", tuple(RuntimePlaneAxis)) +def test_original_artifact_admission_and_full_stack_shape_keep_2d_planes(axis): + labels = np.zeros((2, 8, 9), dtype=np.int32) + labels[0, 1:3, 2:5] = 29 + labels[1, 2:5, 3:7] = 106 + source = _source(labels, axis=axis) + source_bytes = labels.tobytes() + spec = ArtifactSpec.input("saved_labels", ObjectLabelsArtifactType, parameter_name="labels") + value = RuntimeArtifactTypeStrategy.for_artifact_type(spec.artifact_type).runtime_input_value( + RuntimeArtifactInputRequest(spec=spec, value=source) + ) + assert value.domain.scope is ObjectLabelDomainScope.PLANE + assert value.plane_axis is axis + assert value.domain.declared_object_id_domains == ((29,), (106,)) + assert value.source_provenance.identity() == source.metadata.source_provenance.identity() + planes = value.measurement_planes() + assert tuple(plane.labels.shape for plane in planes) == ((8, 9), (8, 9)) + for index, plane in enumerate(planes): + np.testing.assert_array_equal(plane.labels, labels[index]) + assert plane.parent_image_source_voxel_spacing == SourceVoxelSpacing((1.3556, 1.3556)) + + contract = CallableContract.from_callable(measure_object_size_shape) + _image, rows = CellProfilerFunctionContractExecutor().execute( + contract, contract.resolve_canonical_raw_callable(), source, + {"labels": value, "calculate_advanced": False, "calculate_zernikes": False}, + execution_mode=ImagePayloadExecutionMode.FULL_STACK, + ) + area = MeasureObjectSizeShapeModule.MeasurementFeature.AREA.value + # The original AreaShape owner declares ROW_SEQUENCE and a dense extent + # through each plane's maximum ID, not two sparse-ID measurement rows. + # Check the entire existing vector, including every missing-value slot. + expected_area = np.full(29 + 106, np.nan) + expected_area[0] = 6.0 + expected_area[29] = 12.0 + np.testing.assert_array_equal(tuple(row[area] for row in rows), expected_area) + assert "AreaShape_Volume" not in tuple(field.name for field in rows.fields) + assert labels.tobytes() == source_bytes + + +def test_singleton_runtime_slice_is_not_a_physical_volume(): + labels = np.zeros((1, 6, 7), dtype=np.int32) + labels[0, 1:4, 2:5] = 61 + value = SourceImageObjectLabelBuildRequest(image=_source(labels), labels=labels).payload() + assert value.domain.declared_object_id_domains == ((61,),) + assert value.measurement_planes()[0].labels.shape == (6, 7) + + +def test_declared_runtime_planes_can_each_contain_a_genuine_calibrated_volume(): + labels = np.ones((2, 3, 6, 7), dtype=np.int32) + value = SourceImageObjectLabelBuildRequest( + image=_source(labels, spacing=(2.0, 1.3556, 1.3556)), labels=labels, + ).payload() + assert tuple(plane.labels.shape for plane in value.measurement_planes()) == ((3, 6, 7), (3, 6, 7)) + assert value.parent_image_source_voxel_spacing.spacing_for_ndim(3) == (2.0, 1.3556, 1.3556) + + +def test_undeclared_volume_and_explicit_payload_override_are_not_guessed_planar(): + labels = np.ones((2, 6, 7), dtype=np.int32) + for source, options in ( + (_source(labels, axis=None, spacing=(2.0, 1.3556, 1.3556)), {}), + (_source(labels), {"domain_scope": ObjectLabelDomainScope.PAYLOAD}), + ): + value = SourceImageObjectLabelBuildRequest(image=source, labels=labels, **options).payload() + assert value.domain.scope is ObjectLabelDomainScope.PAYLOAD + assert value.plane_axis is None + assert value.measurement_planes()[0].labels.shape == (2, 6, 7) + with pytest.raises(ValueError, match="Cannot project 2-D source voxel spacing onto 3-D data"): + SourceVoxelSpacing((1.3556, 1.3556)).spacing_for_ndim(3) + + +@pytest.mark.parametrize("plane_count", (0, 1, 3)) +def test_declared_axis_rejects_missing_or_conflicting_cardinality(plane_count): + labels = np.ones((2, 6, 7), dtype=np.int32) + with pytest.raises(ValueError): + SourceImageObjectLabelBuildRequest(image=_source(labels, plane_count=plane_count), labels=labels).payload() + + +def test_declared_axis_rejects_payload_wide_ids_and_mismatched_label_geometry(): + labels = np.ones((2, 6, 7), dtype=np.int32) + source = _source(labels) + with pytest.raises(ValueError, match="per-plane domains"): + SourceImageObjectLabelBuildRequest(image=source, labels=labels, declared_object_ids=(1,)).payload() + with pytest.raises(ValueError, match="spatial shape"): + SourceImageObjectLabelBuildRequest(image=source, labels=np.ones((2, 5, 7), dtype=np.int32)).payload() + + +def test_explicit_projection_conflicting_with_source_declaration_is_rejected(): + labels = np.ones((2, 6, 7), dtype=np.int32) + with pytest.raises(ValueError, match="conflicts"): + SourceImageObjectLabelBuildRequest( + image=_source(labels), labels=labels, + plane_projection=RuntimePlaneAxisValueProjection.preserve(axis=RuntimePlaneAxis.SOURCE_BINDING, axis_size=2), + ).payload() + + +class PhysicalCalibrationRequired: + """Independent admission capability for a new physical-measurement leaf.""" + + def payload(self, **kwargs): + SourceVoxelSpacing.require_physical_pixel_size((self.metadata.source_voxel_spacing,)) + return super().payload(**kwargs) + + +class CalibratedSavedLabels(PhysicalCalibrationRequired, SourceImageObjectLabelBuildRequest): + """A new declaration composes calibration admission with the existing builder.""" + + +def test_new_calibrated_leaf_executes_cooperative_admission_and_plane_building(): + labels = np.ones((2, 6, 7), dtype=np.int32) + value = CalibratedSavedLabels(image=_source(labels), labels=labels).payload() + assert value.domain.scope is ObjectLabelDomainScope.PLANE + assert len(value.measurement_planes()) == 2 + with pytest.raises(ValueError, match="Physical scalar pixel size requires"): + CalibratedSavedLabels(image=_source(labels, spacing=()), labels=labels).payload() + assert SourceImageObjectLabelBuildRequest(image=_source(labels, spacing=()), labels=labels).payload().domain.scope is ObjectLabelDomainScope.PLANE + + +class PairedSourceAdmission: + """An independent declared requirement limiting a projection to two sources.""" + + def __post_init__(self): + super().__post_init__() + if self.axis_size > 2: + raise ValueError("Paired projection accepts at most two source planes.") + + +class PairedSourceProjection(PairedSourceAdmission, RuntimePlaneAxisValueProjection): + """An independent projection leaf using the unchanged source constructor.""" + + +@pytest.mark.parametrize("axis", tuple(RuntimePlaneAxis)) +def test_source_constructor_admits_a_new_cooperative_projection_capability(axis): + source = _source(np.ones((2, 6, 7), dtype=np.int32), axis=axis) + value = PairedSourceProjection.from_source_declaration(axis, source.metadata.source_provenance) + assert isinstance(value, PairedSourceProjection) + assert value.axis is axis + assert value.axis_size == 2 + assert value.selected_plane(1).require_plane_index() == 1 + bigger = _source(np.ones((3, 6, 7), dtype=np.int32), axis=axis) + with pytest.raises(ValueError, match="at most two source planes"): + PairedSourceProjection.from_source_declaration(axis, bigger.metadata.source_provenance) + assert RuntimePlaneAxisValueProjection.from_source_declaration(axis, bigger.metadata.source_provenance).axis_size == 3 + # Absence is a declaration, not inferred from three source records. + assert PairedSourceProjection.from_source_declaration(None, bigger.metadata.source_provenance) is None diff --git a/validation/reproduce_saved_label_distance_419.py b/validation/reproduce_saved_label_distance_419.py new file mode 100644 index 0000000000..443bd78ab5 --- /dev/null +++ b/validation/reproduce_saved_label_distance_419.py @@ -0,0 +1,46 @@ +"""Unwaived synthetic reproducer for PR394's canonical raw-call boundary. + +Invoke explicitly with pytest. It is intentionally not a passing acceptance +receipt until the existing executor owner repairs the canonical ndarray ABI. +No persisted scientific inputs, jobs, registration or viewer are used. +""" + +from __future__ import annotations + +import numpy as np + +from openhcs.core.aligned_image_payload import ImagePayloadExecutionMode +from openhcs.core.callable_contract import CallableContract +from openhcs.core.runtime_image_values import ImagePayloadMetadata, image_payload_data +from openhcs.core.runtime_plane_projection import RuntimePlaneAxis +from openhcs.core.source_image_provenance import SourceImageProvenancePlanes +from openhcs.core.source_metadata import SourceVoxelSpacing +from openhcs.interop.cellprofiler.runtime.function_contract_execution import CellProfilerFunctionContractExecutor +from openhcs.processing.backends.cellprofiler.morphology import morph, MorphOperation, RepeatMode + + +def test_original_registered_distance_raw_abi_keeps_planar_geometry(): + labels = np.zeros((1, 9, 9), dtype=np.int32) + labels[0, 2:7, 2:7] = 29 + original = labels.copy() + source = ImagePayloadMetadata( + plane_axis=RuntimePlaneAxis.RUNTIME_SLICE, + source_image_names=("saved_foreground",), + source_image_provenance_planes=SourceImageProvenancePlanes.from_components( + paths=("/synthetic/A01_s001_w2_labels.tif",), + component_metadata=({"well": "A01", "site": "1", "channel": "2"},), + ), + source_voxel_spacing=SourceVoxelSpacing((1.3556, 1.3556)), + ).payload_with(labels, None) + contract = CallableContract.from_callable(morph) + result = CellProfilerFunctionContractExecutor().execute( + contract, contract.resolve_canonical_raw_callable(), source, + {"operation": MorphOperation.DISTANCE, "repeat_mode": RepeatMode.ONCE, "rescale_values": False}, + execution_mode=ImagePayloadExecutionMode.NATURAL, + ) + pixels = image_payload_data(result) + assert pixels.shape == labels.shape + assert pixels.dtype == np.float32 + assert pixels[0, 4, 4] == 3.0 + assert pixels[0, 0, 0] == 0.0 + np.testing.assert_array_equal(labels, original) diff --git a/validation/run_pinned_r0_419.py b/validation/run_pinned_r0_419.py new file mode 100644 index 0000000000..5ccce39d56 --- /dev/null +++ b/validation/run_pinned_r0_419.py @@ -0,0 +1,58 @@ +"""Run the original R0 directly from retained Git objects, without a checkout. + +No detector is copied or altered. Git declares available modules at the CI pin; +Python's original importer contracts load their immutable source on demand. +""" + +from __future__ import annotations + +import importlib.abc +import importlib.util +from pathlib import Path +import subprocess +import sys + + +REPO = Path("/home/ts/.agent-comms") +REVISION = "3b03785f45df2ef5dc62ba6aed99294192ecbb01" +BACKING = Path("/home/ts/wt/basicpy-live-candidate-20260930/.venv/lib/python3.12/site-packages") + + +class GitSourceLoader(importlib.abc.SourceLoader): + """Read one original module from its exact Git blob, never a replacement.""" + + def __init__(self, relative: str): + self.relative = relative + + def get_filename(self, fullname): + return f"{REPO}@{REVISION}/{self.relative}" + + def get_data(self, path): + return subprocess.check_output(("git", "-C", str(REPO), "show", f"{REVISION}:{self.relative}")) + + +class GitRevisionFinder(importlib.abc.MetaPathFinder): + """Resolve original package membership solely from the pinned Git tree.""" + + def __init__(self): + self.paths = frozenset(subprocess.check_output(( + "git", "-C", str(REPO), "ls-tree", "-r", "--name-only", REVISION, + "--", "src/agent_comms", + ), text=True).splitlines()) + + def find_spec(self, fullname, path=None, target=None): + if fullname.partition(".")[0] != "agent_comms": + return None + relative = "src/" + fullname.replace(".", "/") + for candidate, package in ((relative + "/__init__.py", True), (relative + ".py", False)): + if candidate in self.paths: + return importlib.util.spec_from_loader(fullname, GitSourceLoader(candidate), is_package=package) + raise ModuleNotFoundError(f"Module absent from original pinned Git tree: {fullname}") + + +sys.path.insert(0, str(BACKING)) +sys.meta_path.insert(0, GitRevisionFinder()) +from agent_comms.debt_ratchet import main + +print(f"Original R0 source: {REPO}@{REVISION}; dependency backing: {BACKING}", flush=True) +raise SystemExit(main())