diff --git a/benchmark/results/perf_lazy_catalog_20260929/README.md b/benchmark/results/perf_lazy_catalog_20260929/README.md
new file mode 100644
index 0000000000..b0ea45417a
--- /dev/null
+++ b/benchmark/results/perf_lazy_catalog_20260929/README.md
@@ -0,0 +1,28 @@
+# Lazy execution-server function catalog: official30 1w_1t (2026-09-29)
+
+This report accompanies the lazy catalog initialization change for [OpenHCS issue #165](https://github.com/OpenHCSDev/openhcs/issues/165). Both fresh-server runs used the same CPU-only integration checkout and native CP 4.2.8.1 reference. The control CSV is the completed direct-docstring-parser run; the new run changes only execution-server catalog initialization and its import preflight. Each observation owns a fresh ZMQ server, so `total_seconds` includes that server's startup and shutdown. The 1w_1t preset uses one well and one OpenHCS thread.
+
+All 30 cases succeeded on the final code path. Every case had a lower total, with a paired median saving of 1.171 seconds. All 110 files under the produced `results` directories were byte-identical to the control outputs.
+
+| Sum over 30 observations (seconds) | Control fresh | Lazy catalog fresh | Difference |
+| --- | ---: | ---: | ---: |
+| Server compilation jobs | 58.632 | 83.759 | +25.126 |
+| Server execution jobs | 93.115 | 89.219 | -3.896 |
+| Other measured time (`total - compile - execute`) | 160.110 | 101.289 | -58.822 |
+| Per-observation total | 311.858 | 274.266 | **-37.592** |
+
+The patch moves some registry work into compilation; the execution-job difference is run variation, not a claimed effect of this initialization change. A separately timed full CLI invocation took 296.684 seconds. That wall time includes source preparation outside the per-observation timer and has no matched control wall measurement. The native CP total-phase reference sums to 1,319.357 seconds, making its 5× reference line 263.871 seconds; the new per-observation sum remains 10.395 seconds above that line. The native total-phase and OpenHCS well-throughput timers have different preparation boundaries, so the line is a reference rather than a like-for-like end-to-end ratio.
+
+`fresh_total_breakdown.png` shows the measured time shift and native reference. `lazy_native_execution_speedup.png` and `lazy_native_execution_cdf.png` show execution-only ratios relative to native CP; the patch does not target those ratios. The completed multi-well native-relative scaling figures predate this startup-only change and remain at `/home/ts/code/projects/openhcs-benchmark-runs/official30-four-modes-native-relative-fresh-v2-20260928`.
+
+Validation: 104 focused tests passed after the final import-guard change. A live client connected in 1.795 seconds and fetched the complete 266-function catalog on demand in a further 1.616 seconds. The benchmark's ordinary ZMQ outcome and progress evidence path was used throughout.
+
+Fresh benchmark command:
+
+```bash
+OPENHCS_CPU_ONLY=true .venv/bin/python scripts/benchmark_cppipe_well_throughput.py \
+ --manifest benchmark/manifests/official30_portable_axis1.json \
+ --output-dir /path/to/output \
+ --native-summary-csv benchmark/results/perf_lazy_catalog_20260929/native_cp_summary.csv \
+ --mode 1w_1t
+```
diff --git a/benchmark/results/perf_lazy_catalog_20260929/control_fresh.csv b/benchmark/results/perf_lazy_catalog_20260929/control_fresh.csv
new file mode 100644
index 0000000000..d81a262e71
--- /dev/null
+++ b/benchmark/results/perf_lazy_catalog_20260929/control_fresh.csv
@@ -0,0 +1,31 @@
+case_name,mode_name,worker_count,well_count,compile_seconds,prepare_seconds,execute_seconds,total_seconds,wells_per_second,successful_wells,native_single_sample_execution_seconds,projected_native_execution_seconds,projected_execution_speedup,peak_memory_mb,status,memory_limit_mb,error_message,execution_route,server_lifecycle,run_input_sha256
+ExampleColocalization,1w_1t,1,1,2.2928268909454346,0.0,3.9878079891204834,11.62109541380778,0.25076433036098894,1,37.035618890076876,37.035618890076876,9.287212170474922,1344.6640625,success,,,ordinary-zmq-outcomes-v1,fresh-per-observation,dbed67c7d17c4e678119e0e634ed4eb2a7c6b0d51b7b581196590fed56cc8818
+ExampleCometAssay,1w_1t,1,1,2.0185365676879883,0.0,2.8911311626434326,9.938480501063168,0.3458853797161092,1,13.304211451206356,13.304211451206356,4.601732229623919,1263.62109375,success,,,ordinary-zmq-outcomes-v1,fresh-per-observation,dbed67c7d17c4e678119e0e634ed4eb2a7c6b0d51b7b581196590fed56cc8818
+ExampleFly,1w_1t,1,1,2.2488327026367188,0.0,2.1445205211639404,10.066884044092149,0.46630470080894776,1,8.094948755111545,8.094948755111545,3.774712657316053,946.58203125,success,,,ordinary-zmq-outcomes-v1,fresh-per-observation,dbed67c7d17c4e678119e0e634ed4eb2a7c6b0d51b7b581196590fed56cc8818
+ExampleFlyURL,1w_1t,1,1,1.9677801132202148,0.0,1.019911527633667,8.41873428830877,0.9804772011158023,1,4.900778113398701,4.900778113398701,4.80510120791474,883.3203125,success,,,ordinary-zmq-outcomes-v1,fresh-per-observation,dbed67c7d17c4e678119e0e634ed4eb2a7c6b0d51b7b581196590fed56cc8818
+ExampleHuman,1w_1t,1,1,1.923978567123413,0.0,1.0841801166534424,8.417618672829121,0.9223559670940262,1,4.420192994643003,4.420192994643003,4.0769913843161865,852.3828125,success,,,ordinary-zmq-outcomes-v1,fresh-per-observation,dbed67c7d17c4e678119e0e634ed4eb2a7c6b0d51b7b581196590fed56cc8818
+ExampleIlluminationCorrection_Example1_AllMethod,1w_1t,1,1,1.5901720523834229,0.0,4.088348627090454,10.868056402076036,0.24459753587884892,1,946.6214662808925,946.6214662808925,231.54127806232916,1269.7265625,success,,,ordinary-zmq-outcomes-v1,fresh-per-observation,dbed67c7d17c4e678119e0e634ed4eb2a7c6b0d51b7b581196590fed56cc8818
+ExampleIlluminationCorrection_Example1_EachMethod,1w_1t,1,1,1.5006680488586426,0.0,0.17162799835205078,6.682493566069752,5.826555163504015,1,4.54475614009425,4.54475614009425,26.48027235493273,790.26953125,success,,,ordinary-zmq-outcomes-v1,fresh-per-observation,dbed67c7d17c4e678119e0e634ed4eb2a7c6b0d51b7b581196590fed56cc8818
+ExampleIlluminationCorrection_Example2,1w_1t,1,1,1.881812334060669,0.0,2.101905107498169,9.374385974835604,0.47575887057540306,1,48.04419008316472,48.04419008316472,22.85744961167643,995.20703125,success,,,ordinary-zmq-outcomes-v1,fresh-per-observation,dbed67c7d17c4e678119e0e634ed4eb2a7c6b0d51b7b581196590fed56cc8818
+ExampleIlluminationCorrection_Example3,1w_1t,1,1,1.8129961490631104,0.0,0.7289443016052246,7.743487971834838,1.3718469268473292,1,2.1520505752414465,2.1520505752414465,2.9522839680650055,827.015625,success,,,ordinary-zmq-outcomes-v1,fresh-per-observation,dbed67c7d17c4e678119e0e634ed4eb2a7c6b0d51b7b581196590fed56cc8818
+ExampleImagingFlowCytometryObjectsInGrid,1w_1t,1,1,2.560279607772827,0.0,23.013134479522705,30.937172566074878,0.04345344615657676,1,61.60158259188756,61.60158259188756,2.6768010523165024,2518.06640625,success,,,ordinary-zmq-outcomes-v1,fresh-per-observation,dbed67c7d17c4e678119e0e634ed4eb2a7c6b0d51b7b581196590fed56cc8818
+ExampleNeighbors,1w_1t,1,1,1.74615478515625,0.0,1.3547496795654297,8.286614634096622,0.7381437435148723,1,4.5466188420541584,4.5466188420541584,3.3560582524091105,901.8671875,success,,,ordinary-zmq-outcomes-v1,fresh-per-observation,dbed67c7d17c4e678119e0e634ed4eb2a7c6b0d51b7b581196590fed56cc8818
+ExamplePercentPositive,1w_1t,1,1,1.7290244102478027,0.0,0.42984962463378906,7.382856552023441,2.326394959288266,1,2.5050158216618,2.5050158216618,5.827656180451365,842.484375,success,,,ordinary-zmq-outcomes-v1,fresh-per-observation,dbed67c7d17c4e678119e0e634ed4eb2a7c6b0d51b7b581196590fed56cc8818
+ExampleSpeckles,1w_1t,1,1,1.637129306793213,0.0,0.822502613067627,7.375865648966283,1.2158016085448948,1,3.179383432958275,3.179383432958275,3.86549949197166,976.84765625,success,,,ordinary-zmq-outcomes-v1,fresh-per-observation,dbed67c7d17c4e678119e0e634ed4eb2a7c6b0d51b7b581196590fed56cc8818
+ExampleTrackObjects,1w_1t,1,1,1.716566562652588,0.0,3.287581205368042,10.32921796804294,0.3041749960022815,1,9.587221414782107,9.587221414782107,2.916193035514335,1670.55078125,success,,,ordinary-zmq-outcomes-v1,fresh-per-observation,dbed67c7d17c4e678119e0e634ed4eb2a7c6b0d51b7b581196590fed56cc8818
+ExampleTumor,1w_1t,1,1,1.6034469604492188,0.0,0.8798391819000244,7.372601582668722,1.1365713423224535,1,4.360487373080105,4.360487373080105,4.956004986801763,1072.33203125,success,,,ordinary-zmq-outcomes-v1,fresh-per-observation,dbed67c7d17c4e678119e0e634ed4eb2a7c6b0d51b7b581196590fed56cc8818
+ExampleUntangleAndStraightenWorms,1w_1t,1,1,2.0078978538513184,0.0,1.2335312366485596,8.449991872068495,0.8106807272403965,1,3.4416790287941694,3.4416790287941694,2.790102857990879,888.4375,success,,,ordinary-zmq-outcomes-v1,fresh-per-observation,dbed67c7d17c4e678119e0e634ed4eb2a7c6b0d51b7b581196590fed56cc8818
+ExampleUntangleWorms,1w_1t,1,1,2.0958409309387207,0.0,2.062998056411743,10.002663507126272,0.48473143098318805,1,4.618807300925255,4.618807300925255,2.238881072413095,934.63671875,success,,,ordinary-zmq-outcomes-v1,fresh-per-observation,dbed67c7d17c4e678119e0e634ed4eb2a7c6b0d51b7b581196590fed56cc8818
+ExampleUntangleWormsBrightField,1w_1t,1,1,2.1711883544921875,0.0,3.5632073879241943,11.496679156087339,0.2806460278986362,1,7.377188352867961,7.377188352867961,2.0703786082924758,1045.79296875,success,,,ordinary-zmq-outcomes-v1,fresh-per-observation,dbed67c7d17c4e678119e0e634ed4eb2a7c6b0d51b7b581196590fed56cc8818
+ExampleVitra,1w_1t,1,1,1.8910613059997559,0.0,1.2376892566680908,8.538714677095413,0.8079572433972968,1,4.122247557155788,4.122247557155788,3.330599772880831,960.13671875,success,,,ordinary-zmq-outcomes-v1,fresh-per-observation,dbed67c7d17c4e678119e0e634ed4eb2a7c6b0d51b7b581196590fed56cc8818
+ExampleWoundHealing,1w_1t,1,1,1.5049092769622803,0.0,2.042593240737915,8.341959646902978,0.4895737340434634,1,4.702593941241503,4.702593941241503,2.3022664755037696,1272.14453125,success,,,ordinary-zmq-outcomes-v1,fresh-per-observation,dbed67c7d17c4e678119e0e634ed4eb2a7c6b0d51b7b581196590fed56cc8818
+ExampleYeastColonies,1w_1t,1,1,2.1904988288879395,0.0,2.0774261951446533,10.033609306905419,0.48136487464016453,1,12.096297012176365,12.096297012176365,5.8227324948764725,1121.2578125,success,,,ordinary-zmq-outcomes-v1,fresh-per-observation,dbed67c7d17c4e678119e0e634ed4eb2a7c6b0d51b7b581196590fed56cc8818
+ExampleYeastPatches,1w_1t,1,1,2.182415246963501,0.0,2.6008615493774414,10.576405676081777,0.3844879787005065,1,5.990533472970128,5.990533472970128,2.30328810636001,1177.07421875,success,,,ordinary-zmq-outcomes-v1,fresh-per-observation,dbed67c7d17c4e678119e0e634ed4eb2a7c6b0d51b7b581196590fed56cc8818
+cp_tutorial_3d_monolayer,1w_1t,1,1,2.876032829284668,0.0,10.151128053665161,18.547642110381275,0.09851121911903579,1,14.058660756796598,14.058660756796598,1.3849358103329792,1453.578125,success,,,ordinary-zmq-outcomes-v1,fresh-per-observation,dbed67c7d17c4e678119e0e634ed4eb2a7c6b0d51b7b581196590fed56cc8818
+cp_tutorial_advanced_segmentation_final,1w_1t,1,1,3.3548684120178223,0.0,10.546051740646362,20.040677363052964,0.09482221636992562,1,36.253466514870524,36.253466514870524,3.437634046032906,1147.62890625,success,,,ordinary-zmq-outcomes-v1,fresh-per-observation,dbed67c7d17c4e678119e0e634ed4eb2a7c6b0d51b7b581196590fed56cc8818
+cp_tutorial_quality_control,1w_1t,1,1,1.3814642429351807,0.0,0.6194014549255371,7.224075731821358,1.6144618196291087,1,4.787729676347226,4.787729676347226,7.729606765167826,855.1953125,success,,,ordinary-zmq-outcomes-v1,fresh-per-observation,dbed67c7d17c4e678119e0e634ed4eb2a7c6b0d51b7b581196590fed56cc8818
+cp_tutorial_beginner_segmentation_final,1w_1t,1,1,2.4305648803710938,0.0,6.888291358947754,14.83460831688717,0.14517388244633697,1,16.074153264053166,16.074153264053166,2.333547236380058,1046.05078125,success,,,ordinary-zmq-outcomes-v1,fresh-per-observation,dbed67c7d17c4e678119e0e634ed4eb2a7c6b0d51b7b581196590fed56cc8818
+cp_tutorial_pixel_based_classification,1w_1t,1,1,1.6967191696166992,0.0,0.8674452304840088,7.88223431725055,1.1528105347262438,1,4.208680049050599,4.208680049050599,4.851810697837696,1035.89453125,success,,,ordinary-zmq-outcomes-v1,fresh-per-observation,dbed67c7d17c4e678119e0e634ed4eb2a7c6b0d51b7b581196590fed56cc8818
+cp_tutorial_translocation_final,1w_1t,1,1,1.854893445968628,0.0,0.8097820281982422,7.803559121210128,1.2349002141045178,1,3.004684013314545,3.004684013314545,3.710484931358554,931.90625,success,,,ordinary-zmq-outcomes-v1,fresh-per-observation,dbed67c7d17c4e678119e0e634ed4eb2a7c6b0d51b7b581196590fed56cc8818
+cp4_supplement_combine_objects,1w_1t,1,1,1.3613243103027344,0.0,0.14962530136108398,6.642139645293355,6.683361643407789,1,1.8334413380362093,1.8334413380362093,12.253551514069457,825.0390625,success,,,ordinary-zmq-outcomes-v1,fresh-per-observation,dbed67c7d17c4e678119e0e634ed4eb2a7c6b0d51b7b581196590fed56cc8818
+cp_tutorial_translocation_start,1w_1t,1,1,1.402390956878662,0.0,0.25930023193359375,6.627473204862326,3.856533380410157,1,2.1760300607420504,2.1760300607420504,8.39193256602766,866.1328125,success,,,ordinary-zmq-outcomes-v1,fresh-per-observation,dbed67c7d17c4e678119e0e634ed4eb2a7c6b0d51b7b581196590fed56cc8818
diff --git a/benchmark/results/perf_lazy_catalog_20260929/fresh_total_breakdown.png b/benchmark/results/perf_lazy_catalog_20260929/fresh_total_breakdown.png
new file mode 100644
index 0000000000..4c3fc64c77
Binary files /dev/null and b/benchmark/results/perf_lazy_catalog_20260929/fresh_total_breakdown.png differ
diff --git a/benchmark/results/perf_lazy_catalog_20260929/fresh_total_breakdown.svg b/benchmark/results/perf_lazy_catalog_20260929/fresh_total_breakdown.svg
new file mode 100644
index 0000000000..1d79493efa
--- /dev/null
+++ b/benchmark/results/perf_lazy_catalog_20260929/fresh_total_breakdown.svg
@@ -0,0 +1,1622 @@
+
+
+
diff --git a/benchmark/results/perf_lazy_catalog_20260929/lazy_fresh.csv b/benchmark/results/perf_lazy_catalog_20260929/lazy_fresh.csv
new file mode 100644
index 0000000000..a2fe0eb6a4
--- /dev/null
+++ b/benchmark/results/perf_lazy_catalog_20260929/lazy_fresh.csv
@@ -0,0 +1,31 @@
+case_name,mode_name,worker_count,well_count,compile_seconds,prepare_seconds,execute_seconds,total_seconds,wells_per_second,successful_wells,native_single_sample_execution_seconds,projected_native_execution_seconds,projected_execution_speedup,peak_memory_mb,status,memory_limit_mb,error_message,execution_route,server_lifecycle,run_input_sha256
+ExampleColocalization,1w_1t,1,1,3.3051583766937256,0.0,3.6666457653045654,10.503191142808646,0.2727288273829027,1,37.035618890076876,37.035618890076876,10.100680911290747,1321.0546875,success,,,ordinary-zmq-outcomes-v1,fresh-per-observation,6d8da1f92a4266752424d89e1bf8a178d54dd542f74cf87ffca80c48113a99be
+ExampleCometAssay,1w_1t,1,1,3.030191659927368,0.0,2.557861566543579,8.700058875139803,0.39095157184416873,1,13.304211451206356,13.304211451206356,5.2013023789963135,1231.8828125,success,,,ordinary-zmq-outcomes-v1,fresh-per-observation,6d8da1f92a4266752424d89e1bf8a178d54dd542f74cf87ffca80c48113a99be
+ExampleFly,1w_1t,1,1,2.995745897293091,0.0,2.165245532989502,8.828781486023217,0.46184138693006527,1,8.094948755111545,8.094948755111545,3.7385823601885213,910.81640625,success,,,ordinary-zmq-outcomes-v1,fresh-per-observation,6d8da1f92a4266752424d89e1bf8a178d54dd542f74cf87ffca80c48113a99be
+ExampleFlyURL,1w_1t,1,1,2.714168071746826,0.0,1.01365065574646,7.007350472267717,0.9865331752423052,1,4.900778113398701,4.900778113398701,4.834780193369214,828.10546875,success,,,ordinary-zmq-outcomes-v1,fresh-per-observation,6d8da1f92a4266752424d89e1bf8a178d54dd542f74cf87ffca80c48113a99be
+ExampleHuman,1w_1t,1,1,2.648146629333496,0.0,1.2065091133117676,7.4798929137177765,0.8288375023169803,1,4.420192994643003,4.420192994643003,3.6636217214389197,799.84765625,success,,,ordinary-zmq-outcomes-v1,fresh-per-observation,6d8da1f92a4266752424d89e1bf8a178d54dd542f74cf87ffca80c48113a99be
+ExampleIlluminationCorrection_Example1_AllMethod,1w_1t,1,1,2.5387473106384277,0.0,2.738597869873047,8.265587457921356,0.36515036070131646,1,946.6214662808925,946.6214662808925,345.659169860077,1312.6953125,success,,,ordinary-zmq-outcomes-v1,fresh-per-observation,6d8da1f92a4266752424d89e1bf8a178d54dd542f74cf87ffca80c48113a99be
+ExampleIlluminationCorrection_Example1_EachMethod,1w_1t,1,1,2.454306125640869,0.0,0.1676487922668457,5.733787109144032,5.964850605116828,1,4.54475614009425,4.54475614009425,27.10879141234961,759.90625,success,,,ordinary-zmq-outcomes-v1,fresh-per-observation,6d8da1f92a4266752424d89e1bf8a178d54dd542f74cf87ffca80c48113a99be
+ExampleIlluminationCorrection_Example2,1w_1t,1,1,2.9105353355407715,0.0,1.7648985385894775,7.91399956215173,0.5666048093615675,1,48.04419008316472,48.04419008316472,27.22206916300246,1000.71875,success,,,ordinary-zmq-outcomes-v1,fresh-per-observation,6d8da1f92a4266752424d89e1bf8a178d54dd542f74cf87ffca80c48113a99be
+ExampleIlluminationCorrection_Example3,1w_1t,1,1,2.9293508529663086,0.0,0.8705692291259766,6.964360218960792,1.148673725814968,1,2.1520505752414465,2.1520505752414465,2.472003952404837,794.453125,success,,,ordinary-zmq-outcomes-v1,fresh-per-observation,6d8da1f92a4266752424d89e1bf8a178d54dd542f74cf87ffca80c48113a99be
+ExampleImagingFlowCytometryObjectsInGrid,1w_1t,1,1,3.428496837615967,0.0,21.203369855880737,28.11586388805881,0.04716231461305434,1,61.60158259188756,61.60158259188756,2.9052732188606525,2432.64453125,success,,,ordinary-zmq-outcomes-v1,fresh-per-observation,6d8da1f92a4266752424d89e1bf8a178d54dd542f74cf87ffca80c48113a99be
+ExampleNeighbors,1w_1t,1,1,2.427239179611206,0.0,1.3531577587127686,6.883681884035468,0.7390121318531844,1,4.5466188420541584,4.5466188420541584,3.3600064831903005,836.2109375,success,,,ordinary-zmq-outcomes-v1,fresh-per-observation,6d8da1f92a4266752424d89e1bf8a178d54dd542f74cf87ffca80c48113a99be
+ExamplePercentPositive,1w_1t,1,1,2.431612253189087,0.0,0.44060468673706055,6.032959253992885,2.269608177356428,1,2.5050158216618,2.5050158216618,5.685404393250853,793.640625,success,,,ordinary-zmq-outcomes-v1,fresh-per-observation,6d8da1f92a4266752424d89e1bf8a178d54dd542f74cf87ffca80c48113a99be
+ExampleSpeckles,1w_1t,1,1,2.3191630840301514,0.0,0.8265681266784668,6.392104679252952,1.2098216320274322,1,3.179383432958275,3.179383432958275,3.8464868537025603,895.76171875,success,,,ordinary-zmq-outcomes-v1,fresh-per-observation,6d8da1f92a4266752424d89e1bf8a178d54dd542f74cf87ffca80c48113a99be
+ExampleTrackObjects,1w_1t,1,1,2.427124261856079,0.0,3.2250688076019287,8.820541792083532,0.310070903803002,1,9.587221414782107,9.587221414782107,2.9727184090409833,1596.9609375,success,,,ordinary-zmq-outcomes-v1,fresh-per-observation,6d8da1f92a4266752424d89e1bf8a178d54dd542f74cf87ffca80c48113a99be
+ExampleTumor,1w_1t,1,1,2.293205499649048,0.0,0.8080277442932129,6.27411754289642,1.2375812675525226,1,4.360487373080105,4.360487373080105,5.396457490323245,953.5,success,,,ordinary-zmq-outcomes-v1,fresh-per-observation,6d8da1f92a4266752424d89e1bf8a178d54dd542f74cf87ffca80c48113a99be
+ExampleUntangleAndStraightenWorms,1w_1t,1,1,3.00498628616333,0.0,1.243178367614746,7.572613257914782,0.8043898012146672,1,3.4416790287941694,3.4416790287941694,2.7684515098164306,863.2265625,success,,,ordinary-zmq-outcomes-v1,fresh-per-observation,6d8da1f92a4266752424d89e1bf8a178d54dd542f74cf87ffca80c48113a99be
+ExampleUntangleWorms,1w_1t,1,1,3.205960750579834,0.0,2.200486660003662,8.85065891686827,0.4544449271954849,1,4.618807300925255,4.618807300925255,2.0989935475989516,924.0546875,success,,,ordinary-zmq-outcomes-v1,fresh-per-observation,6d8da1f92a4266752424d89e1bf8a178d54dd542f74cf87ffca80c48113a99be
+ExampleUntangleWormsBrightField,1w_1t,1,1,3.292342185974121,0.0,3.7398955821990967,10.747698435094208,0.267387144379039,1,7.377188352867961,7.377188352867961,1.9725653272196704,1023.015625,success,,,ordinary-zmq-outcomes-v1,fresh-per-observation,6d8da1f92a4266752424d89e1bf8a178d54dd542f74cf87ffca80c48113a99be
+ExampleVitra,1w_1t,1,1,2.898782253265381,0.0,1.2529144287109375,7.474349890835583,0.7981391043830912,1,4.122247557155788,4.122247557155788,3.290126973313706,934.3515625,success,,,ordinary-zmq-outcomes-v1,fresh-per-observation,6d8da1f92a4266752424d89e1bf8a178d54dd542f74cf87ffca80c48113a99be
+ExampleWoundHealing,1w_1t,1,1,2.021925210952759,0.0,1.4669053554534912,6.312976646237075,0.6817072391768941,1,4.702593941241503,4.702593941241503,3.205792332653734,1197.5,success,,,ordinary-zmq-outcomes-v1,fresh-per-observation,6d8da1f92a4266752424d89e1bf8a178d54dd542f74cf87ffca80c48113a99be
+ExampleYeastColonies,1w_1t,1,1,3.246541738510132,0.0,2.0734219551086426,9.27478964207694,0.48229449752672376,1,12.096297012176365,12.096297012176365,5.83397748942161,1116.33203125,success,,,ordinary-zmq-outcomes-v1,fresh-per-observation,6d8da1f92a4266752424d89e1bf8a178d54dd542f74cf87ffca80c48113a99be
+ExampleYeastPatches,1w_1t,1,1,3.228555202484131,0.0,2.6230390071868896,9.73673579795286,0.3812371822378891,1,5.990533472970128,5.990533472970128,2.2838141013368873,1104.23828125,success,,,ordinary-zmq-outcomes-v1,fresh-per-observation,6d8da1f92a4266752424d89e1bf8a178d54dd542f74cf87ffca80c48113a99be
+cp_tutorial_3d_monolayer,1w_1t,1,1,3.563236713409424,0.0,10.151130676269531,17.0197413158603,0.09851119366808239,1,14.058660756796598,14.058660756796598,1.3849354525266595,1395.6328125,success,,,ordinary-zmq-outcomes-v1,fresh-per-observation,6d8da1f92a4266752424d89e1bf8a178d54dd542f74cf87ffca80c48113a99be
+cp_tutorial_advanced_segmentation_final,1w_1t,1,1,4.281343460083008,0.0,10.925135135650635,19.630296141374856,0.091532048581882,1,36.253466514870524,36.253466514870524,3.3183540583007614,1098.890625,success,,,ordinary-zmq-outcomes-v1,fresh-per-observation,6d8da1f92a4266752424d89e1bf8a178d54dd542f74cf87ffca80c48113a99be
+cp_tutorial_quality_control,1w_1t,1,1,1.9249956607818604,0.0,0.6149721145629883,6.064614792820066,1.6260899906179005,1,4.787729676347226,4.787729676347226,7.785279304492504,804.34765625,success,,,ordinary-zmq-outcomes-v1,fresh-per-observation,6d8da1f92a4266752424d89e1bf8a178d54dd542f74cf87ffca80c48113a99be
+cp_tutorial_beginner_segmentation_final,1w_1t,1,1,3.191765785217285,0.0,6.749016046524048,14.025305974297225,0.14816974698334448,1,16.074153264053166,16.074153264053166,2.381703222106258,969.4296875,success,,,ordinary-zmq-outcomes-v1,fresh-per-observation,6d8da1f92a4266752424d89e1bf8a178d54dd542f74cf87ffca80c48113a99be
+cp_tutorial_pixel_based_classification,1w_1t,1,1,2.38506817817688,0.0,0.8117902278900146,6.388479145243764,1.2318453285637296,1,4.208680049050599,4.208680049050599,5.184442857842349,989.24609375,success,,,ordinary-zmq-outcomes-v1,fresh-per-observation,6d8da1f92a4266752424d89e1bf8a178d54dd542f74cf87ffca80c48113a99be
+cp_tutorial_translocation_final,1w_1t,1,1,2.5704596042633057,0.0,0.9488544464111328,6.581289496738464,1.0539024228450589,1,3.004684013314545,3.004684013314545,3.1666437615160143,877.51171875,success,,,ordinary-zmq-outcomes-v1,fresh-per-observation,6d8da1f92a4266752424d89e1bf8a178d54dd542f74cf87ffca80c48113a99be
+cp4_supplement_combine_objects,1w_1t,1,1,2.008012294769287,0.0,0.15258502960205078,5.45942115271464,6.553722882304043,1,1.8334413380362093,1.8334413380362093,12.015866450450048,775.21875,success,,,ordinary-zmq-outcomes-v1,fresh-per-observation,6d8da1f92a4266752424d89e1bf8a178d54dd542f74cf87ffca80c48113a99be
+cp_tutorial_translocation_start,1w_1t,1,1,2.0814247131347656,0.0,0.25717926025390625,5.210829641204327,3.88833842593966,1,2.1760300607420504,2.1760300607420504,8.461141301183128,801.15234375,success,,,ordinary-zmq-outcomes-v1,fresh-per-observation,6d8da1f92a4266752424d89e1bf8a178d54dd542f74cf87ffca80c48113a99be
diff --git a/benchmark/results/perf_lazy_catalog_20260929/lazy_native_execution_cdf.png b/benchmark/results/perf_lazy_catalog_20260929/lazy_native_execution_cdf.png
new file mode 100644
index 0000000000..9e220c446d
Binary files /dev/null and b/benchmark/results/perf_lazy_catalog_20260929/lazy_native_execution_cdf.png differ
diff --git a/benchmark/results/perf_lazy_catalog_20260929/lazy_native_execution_speedup.png b/benchmark/results/perf_lazy_catalog_20260929/lazy_native_execution_speedup.png
new file mode 100644
index 0000000000..a8709fd103
Binary files /dev/null and b/benchmark/results/perf_lazy_catalog_20260929/lazy_native_execution_speedup.png differ
diff --git a/benchmark/results/perf_lazy_catalog_20260929/native_cp_summary.csv b/benchmark/results/perf_lazy_catalog_20260929/native_cp_summary.csv
new file mode 100644
index 0000000000..32394feaf5
--- /dev/null
+++ b/benchmark/results/perf_lazy_catalog_20260929/native_cp_summary.csv
@@ -0,0 +1,31 @@
+case_name,assay_category,module_category,n,equivalent_count,median_native_execution_seconds,median_openhcs_execution_seconds,median_native_total_phase_seconds,median_openhcs_total_phase_seconds,median_native_peak_memory_mb,median_openhcs_peak_memory_mb,median_speedup,median_total_phase_speedup,speedup_target,meets_execution_speedup_target,meets_total_phase_speedup_target,meets_speedup_target,min_parity_accuracy
+ExampleColocalization,,,1,1,37.035618890076876,17.959853410720825,39.35332336090505,26.953527031932026,,,2.062133695811186,1.4600435525296152,5.0,False,False,False,1.0
+ExampleCometAssay,,,1,1,13.304211451206356,2.57122540473938,14.30461646290496,8.059360695071518,,,5.1742688239947885,1.774907093021976,5.0,True,False,True,1.0
+ExampleFly,,,1,1,8.094948755111545,2.572516441345215,9.810052920132875,16.424860467668623,,,3.1467043805864083,0.5972685697661414,5.0,False,False,False,1.0
+ExampleFlyURL,,,1,1,4.900778113398701,1.587127923965454,6.021430939435959,8.042698163539171,,,3.0878280442285084,0.7486829440813233,5.0,False,False,False,1.0
+ExampleHuman,,,1,1,4.420192994643003,2.1705381870269775,5.455457073636353,11.446641855407506,,,2.036450232049322,0.47659891368568863,5.0,False,False,False,1.0
+ExampleIlluminationCorrection_Example1_AllMethod,,,1,1,946.6214662808925,6.739018201828003,946.862535060849,9.857038384769112,,,140.46875048120737,96.0595361507287,5.0,True,True,True,1.0
+ExampleIlluminationCorrection_Example1_EachMethod,,,1,1,4.54475614009425,0.2049102783203125,4.6763526406139135,3.222155754920095,,,22.17924926630552,1.4513117913289328,5.0,True,False,True,1.0
+ExampleIlluminationCorrection_Example2,,,1,1,48.04419008316472,2.1667985916137695,48.96783200325444,6.28821934806183,,,22.17289150413504,7.787233442858101,5.0,True,True,True,1.0
+ExampleIlluminationCorrection_Example3,,,1,1,2.1520505752414465,2.0806398391723633,2.7176199601963162,6.080346302129328,,,1.0343215268325772,0.4469515098580174,5.0,False,False,False,1.0
+ExampleImagingFlowCytometryObjectsInGrid,,,1,1,61.60158259188756,36.9328293800354,64.14507223013788,98.14512260677293,,,1.667935644951893,0.6535737133585411,5.0,False,False,False,1.0
+ExampleNeighbors,,,1,1,4.5466188420541584,2.789321184158325,5.234509553294629,14.297266059555113,,,1.6300090745648914,0.3661196155607886,5.0,False,False,False,1.0
+ExamplePercentPositive,,,1,1,2.5050158216618,0.9022600650787354,3.3950326037593186,5.097386521752924,,,2.776378916253155,0.666033974326085,5.0,False,False,False,1.0
+ExampleSpeckles,,,1,1,3.179383432958275,0.9791054725646973,3.897916650865227,4.4375677248463035,,,3.2472328283796696,0.8783903463693576,5.0,False,False,False,1.0
+ExampleTrackObjects,,,1,1,9.587221414782107,3.7285819053649902,10.388708942104131,7.917243284638971,,,2.5712782119623614,1.3121623990335494,5.0,False,False,False,1.0
+ExampleTumor,,,1,1,4.360487373080105,1.1599302291870117,4.82744375616312,4.7034944533370435,,,3.759266948440808,1.026352598914651,5.0,False,False,False,1.0
+ExampleUntangleAndStraightenWorms,,,1,1,3.4416790287941694,2.619752883911133,4.3137561599723995,6.864017297513783,,,1.3137418608948912,0.628459395277877,5.0,False,False,False,1.0
+ExampleUntangleWorms,,,1,1,4.618807300925255,4.506817102432251,5.426323775202036,8.279627295210958,,,1.0248490666356451,0.655382613459025,5.0,False,False,False,1.0
+ExampleUntangleWormsBrightField,,,1,1,7.377188352867961,7.678912878036499,8.610389334149659,13.188176837284118,,,0.960707390491232,0.6528870093557847,5.0,False,False,False,1.0
+ExampleVitra,,,1,1,4.122247557155788,3.466949462890625,4.8610909334383905,12.178178021218628,,,1.1890128775395525,0.39916405598347116,5.0,False,False,False,1.0
+ExampleWoundHealing,,,1,1,4.702593941241503,2.663236141204834,5.02863251324743,5.365988084580749,,,1.7657442644624348,0.9371307639868386,5.0,False,False,False,1.0
+ExampleYeastColonies,,,1,1,12.096297012176365,4.731346368789673,13.198869303334504,16.91469065612182,,,2.5566289316651156,0.7803198752888529,5.0,False,False,False,1.0
+ExampleYeastPatches,,,1,1,5.990533472970128,5.013910531997681,7.104359833989292,10.384889775887132,,,1.1947826820482443,0.684105463544258,5.0,False,False,False,1.0
+cp4_supplement_combine_objects,Object-combination benchmark,Object set algebra,1,1,1.8334413380362093,0.18567681312561035,1.9359478713013232,2.6644571498036385,,,9.874368841067335,0.7265824753248503,5.0,True,False,True,1.0
+cp_tutorial_3d_monolayer,3D monolayer morphology,3D segmentation + measurement,1,1,14.058660756796598,13.644547939300537,15.750524973962456,19.772331691812724,,,1.0303500577181666,0.7965942115205559,5.0,False,False,False,1.0
+cp_tutorial_advanced_segmentation_final,Cell Painting morphology,Advanced segmentation + measurement,1,1,36.253466514870524,21.642004013061523,45.43951385235414,50.77297239517793,,,1.67514369246908,0.8949547703980725,5.0,False,False,False,1.0
+cp_tutorial_beginner_segmentation_final,Cell morphology,Segmentation + intensity measurement,1,1,16.074153264053166,8.612112760543823,18.3711662706919,36.70200763596222,,,1.8664587553586724,0.5005493555805115,5.0,False,False,False,1.0
+cp_tutorial_pixel_based_classification,Pixel classification,Pixel classification,1,1,4.208680049050599,0.9723286628723145,4.7289649839513,4.328970203641802,,,4.328454163449134,1.092399522633119,5.0,False,False,False,1.0
+cp_tutorial_quality_control,Cell Painting quality control,Image quality measurement,1,1,4.787729676347226,1.2474637031555176,8.168980250600725,7.120973748154938,,,3.8379711283273736,1.147171796935402,5.0,False,False,False,1.0
+cp_tutorial_translocation_final,Translocation assay,Segmentation + classification,1,1,3.004684013314545,1.9986815452575684,3.8793991575948894,5.977722632698715,,,1.5033330449485558,0.6489761061134227,5.0,False,False,False,1.0
+cp_tutorial_translocation_start,Translocation assay,Starter nuclei segmentation,1,1,2.1760300607420504,0.33385229110717773,2.4812272735871375,2.8119246223941445,,,6.517942571325569,0.882394660876278,5.0,True,False,True,1.0
diff --git a/openhcs/processing/backends/lib_registry/registry_service.py b/openhcs/processing/backends/lib_registry/registry_service.py
index 8828c56054..7677015900 100644
--- a/openhcs/processing/backends/lib_registry/registry_service.py
+++ b/openhcs/processing/backends/lib_registry/registry_service.py
@@ -64,31 +64,34 @@ def get_all_functions_with_metadata(
cancellation: OperationCancellation | None = None,
) -> Dict[str, FunctionMetadata]:
"""Get unified metadata for all functions from all registries."""
- if cls._metadata_cache is not None:
- logger.debug(
- f"🎯 REGISTRY SERVICE: Using cached metadata ({len(cls._metadata_cache)} functions)"
- )
- return cls._metadata_cache
+ with cls._registry_inventory_lock:
+ if cls._metadata_cache is not None:
+ logger.debug(
+ f"🎯 REGISTRY SERVICE: Using cached metadata ({len(cls._metadata_cache)} functions)"
+ )
+ return cls._metadata_cache
- emit_status = status_callback or logger.debug
- emit_status("Loading cached function catalog")
- registry_instances = cls._available_registry_instances()
- cached_functions = cls._load_valid_persistent_catalog(registry_instances)
- if cached_functions is None:
- cls._prepare_persistent_catalog(
- status_callback=emit_status,
- cancellation=cancellation,
- )
- emit_status("Loading the prepared function catalog")
+ emit_status = status_callback or logger.debug
+ emit_status("Loading cached function catalog")
+ registry_instances = cls._available_registry_instances()
cached_functions = cls._load_valid_persistent_catalog(registry_instances)
- if cached_functions is None:
- raise RuntimeError(
- "Function registry preparation completed without producing a valid "
- "persistent catalog."
- )
- cls._metadata_cache = cached_functions
- emit_status(f"Function catalog ready ({len(cached_functions)} functions)")
- return cached_functions
+ if cached_functions is None:
+ cls._prepare_persistent_catalog(
+ status_callback=emit_status,
+ cancellation=cancellation,
+ )
+ emit_status("Loading the prepared function catalog")
+ cached_functions = cls._load_valid_persistent_catalog(
+ registry_instances
+ )
+ if cached_functions is None:
+ raise RuntimeError(
+ "Function registry preparation completed without producing a valid "
+ "persistent catalog."
+ )
+ cls._metadata_cache = cached_functions
+ emit_status(f"Function catalog ready ({len(cached_functions)} functions)")
+ return cached_functions
@classmethod
def cached_metadata_snapshot(cls) -> Dict[str, FunctionMetadata]:
diff --git a/openhcs/processing/func_registry.py b/openhcs/processing/func_registry.py
index ae0e601379..394e9bc204 100644
--- a/openhcs/processing/func_registry.py
+++ b/openhcs/processing/func_registry.py
@@ -8,15 +8,18 @@
from __future__ import annotations
+import ast
import logging
import sys
import threading
import types
from collections.abc import Callable, Mapping
+from importlib.machinery import PathFinder
from typing import Any
from arraybridge.types import VALID_MEMORY_TYPES
+import openhcs
from openhcs.core.callable_contract import CallableContract
logger = logging.getLogger(__name__)
@@ -27,6 +30,56 @@
_external_projection_modules: set[str] = set()
+def pipeline_source_requires_import_projection(source: str) -> bool:
+ """Admit direct imports without building the external virtual-module view.
+
+ The registry owns virtual ``openhcs.`` modules, while real
+ OpenHCS package children are importable without registry initialization.
+ Dynamic imports conservatively retain the full projection.
+ """
+
+ requested_modules: set[str] = set()
+ for node in ast.walk(ast.parse(source)):
+ if isinstance(node, ast.Import):
+ requested_modules.update(alias.name for alias in node.names)
+ elif isinstance(node, ast.ImportFrom):
+ if node.level:
+ return True
+ if node.module == "openhcs":
+ requested_modules.update(
+ f"openhcs.{alias.name}" for alias in node.names
+ )
+ elif node.module is not None:
+ requested_modules.add(node.module)
+ elif isinstance(node, ast.Call) and (
+ (
+ isinstance(node.func, ast.Name)
+ and node.func.id in {"__import__", "exec", "eval"}
+ )
+ or (
+ isinstance(node.func, ast.Attribute)
+ and node.func.attr == "import_module"
+ )
+ ):
+ if not node.args or not isinstance(node.args[0], ast.Constant):
+ return True
+ imported = node.args[0].value
+ if not isinstance(imported, str):
+ return True
+ if isinstance(node.func, ast.Name) and node.func.id in {"exec", "eval"}:
+ return True
+ requested_modules.add(imported)
+
+ for module_name in requested_modules:
+ parts = module_name.split(".")
+ if len(parts) < 2 or parts[0] != "openhcs":
+ continue
+ top_level_module = f"openhcs.{parts[1]}"
+ if PathFinder.find_spec(top_level_module, openhcs.__path__) is None:
+ return True
+ return False
+
+
def _create_external_virtual_modules(all_functions: Mapping[str, Any]) -> None:
"""Reconcile the canonical external-callable import projection."""
diff --git a/openhcs/runtime/zmq_execution_server.py b/openhcs/runtime/zmq_execution_server.py
index c1b80db0a0..9b60545384 100644
--- a/openhcs/runtime/zmq_execution_server.py
+++ b/openhcs/runtime/zmq_execution_server.py
@@ -393,26 +393,12 @@ def _execute_pipeline(
):
logger.info("[%s] Starting plate %s", execution_id, request_payload.plate_id)
- self._function_catalog_preparation.wait_until_ready()
-
import openhcs.processing.func_registry as func_registry_module
- logger.info(
- "[%s] Registry initialized status BEFORE check: %s",
- execution_id,
- func_registry_module._registry_initialized,
- )
- with func_registry_module._registry_lock:
- if not func_registry_module._registry_initialized:
- logger.info("[%s] Initializing registry...", execution_id)
- func_registry_module._auto_initialize_registry()
- logger.info(
- "[%s] Registry initialized status AFTER init: %s",
- execution_id,
- func_registry_module._registry_initialized,
- )
- else:
- logger.info("[%s] Registry already initialized, skipping", execution_id)
+ if func_registry_module.pipeline_source_requires_import_projection(
+ request_payload.pipeline_code
+ ):
+ func_registry_module.initialize_registry()
self._cleanup_compiled_artifacts()
diff --git a/openhcs/runtime/zmq_execution_server_launcher.py b/openhcs/runtime/zmq_execution_server_launcher.py
index 7d2c9ec678..ae4b7c8a40 100644
--- a/openhcs/runtime/zmq_execution_server_launcher.py
+++ b/openhcs/runtime/zmq_execution_server_launcher.py
@@ -194,10 +194,6 @@ def main(
config=config,
)
- server.prepare_runtime_capabilities(
- lambda status: status_reporter.emit(status.phase, status.message)
- )
-
status_reporter.emit(
EndpointStartupPhase.BINDING_ENDPOINT,
"Binding execution server endpoint",
diff --git a/tests/unit/test_func_registry_projection.py b/tests/unit/test_func_registry_projection.py
index c721f0d91d..140aea754e 100644
--- a/tests/unit/test_func_registry_projection.py
+++ b/tests/unit/test_func_registry_projection.py
@@ -3,7 +3,7 @@
from __future__ import annotations
import sys
-from types import SimpleNamespace
+from types import ModuleType, SimpleNamespace
import pytest
@@ -17,6 +17,33 @@ def public_projection_module(self, metadata):
return metadata.public_module
+@pytest.mark.parametrize(
+ ("source", "expected"),
+ (
+ ("from openhcs.core.config import PipelineConfig", False),
+ ("from openhcs.processing.backends.cellprofiler.crop import crop", False),
+ ("from openhcs.skimage.filters import gaussian", True),
+ ("from openhcs import skimage", True),
+ ("importlib.import_module('openhcs.skimage.filters')", True),
+ ("importlib.import_module(module_name)", True),
+ ),
+)
+def test_pipeline_source_requires_only_missing_virtual_import_projection(
+ source: str, expected: bool
+) -> None:
+ assert func_registry.pipeline_source_requires_import_projection(source) is expected
+
+
+def test_partial_virtual_module_does_not_prove_projection_complete(monkeypatch) -> None:
+ monkeypatch.setitem(
+ sys.modules, "openhcs.codex_virtual", ModuleType("openhcs.codex_virtual")
+ )
+
+ assert func_registry.pipeline_source_requires_import_projection(
+ "from openhcs.codex_virtual.filters import noop"
+ )
+
+
def test_external_projection_removes_stale_exports_and_modules(monkeypatch) -> None:
module_name = "openhcs.codex_external.filters"
diff --git a/tests/unit/test_library_registry_discovery.py b/tests/unit/test_library_registry_discovery.py
index 569611d8ee..65a7f5262e 100644
--- a/tests/unit/test_library_registry_discovery.py
+++ b/tests/unit/test_library_registry_discovery.py
@@ -6,8 +6,10 @@
import subprocess
import sys
import textwrap
+import threading
+import time
from collections.abc import Callable
-from concurrent.futures import CancelledError
+from concurrent.futures import CancelledError, ThreadPoolExecutor
from pathlib import Path
from types import SimpleNamespace
from typing import Any
@@ -16,6 +18,52 @@
import pytest
+def test_concurrent_catalog_requests_share_one_metadata_load(monkeypatch) -> None:
+ from openhcs.processing.backends.lib_registry.registry_service import (
+ RegistryService,
+ )
+
+ metadata = {"test:example": object()}
+ load_calls: list[object] = []
+ start = threading.Barrier(3)
+ loading = threading.Event()
+ release = threading.Event()
+
+ def load_cached(_cls, _instances):
+ load_calls.append(object())
+ loading.set()
+ assert release.wait(timeout=2)
+ return metadata
+
+ monkeypatch.setattr(RegistryService, "_metadata_cache", None)
+ monkeypatch.setattr(
+ RegistryService,
+ "_available_registry_instances",
+ classmethod(lambda _cls: []),
+ )
+ monkeypatch.setattr(
+ RegistryService,
+ "_load_valid_persistent_catalog",
+ classmethod(load_cached),
+ )
+
+ def request_metadata():
+ start.wait(timeout=2)
+ return RegistryService.get_all_functions_with_metadata()
+
+ with ThreadPoolExecutor(max_workers=2) as executor:
+ first = executor.submit(request_metadata)
+ second = executor.submit(request_metadata)
+ start.wait(timeout=2)
+ assert loading.wait(timeout=2)
+ time.sleep(0.05)
+ release.set()
+ assert first.result(timeout=2) is metadata
+ assert second.result(timeout=2) is metadata
+
+ assert len(load_calls) == 1
+
+
def test_declared_library_submodules_are_imported_from_the_package_authority(
tmp_path: Path,
monkeypatch,
diff --git a/tests/unit/test_zmq_execution_server.py b/tests/unit/test_zmq_execution_server.py
index 080ec4c739..5f8a8b5e5c 100644
--- a/tests/unit/test_zmq_execution_server.py
+++ b/tests/unit/test_zmq_execution_server.py
@@ -1,6 +1,7 @@
+import sys
from pathlib import Path
from queue import SimpleQueue
-from types import SimpleNamespace
+from types import ModuleType, SimpleNamespace
import pytest
from objectstate import get_current_global_config
@@ -188,7 +189,11 @@ def test_zmq_server_reconstructs_pipeline_and_configs_for_artifact_execution(
) -> None:
import openhcs.processing.func_registry as func_registry_module
- monkeypatch.setattr(func_registry_module, "_registry_initialized", True)
+ monkeypatch.setattr(
+ func_registry_module,
+ "initialize_registry",
+ lambda: pytest.fail("Direct-import pipeline initialized the full registry"),
+ )
monkeypatch.setattr(
ZMQExecutionServer,
"_cleanup_compiled_artifacts",
@@ -226,6 +231,59 @@ def test_zmq_server_reconstructs_pipeline_and_configs_for_artifact_execution(
assert context.compile_artifact_id == "compile-1"
+def test_zmq_server_prepares_virtual_import_before_evaluating_pipeline(
+ monkeypatch,
+) -> None:
+ import openhcs
+ import openhcs.processing.func_registry as func_registry_module
+
+ initialized: list[str] = []
+
+ def initialize_registry() -> None:
+ initialized.append("registry")
+ package = ModuleType("openhcs.codex_virtual")
+ package.__path__ = []
+ module = ModuleType("openhcs.codex_virtual.filters")
+ module.noop = lambda value: value
+ package.filters = module
+ monkeypatch.setitem(sys.modules, package.__name__, package)
+ monkeypatch.setitem(sys.modules, module.__name__, module)
+ monkeypatch.setattr(openhcs, "codex_virtual", package, raising=False)
+
+ monkeypatch.setattr(
+ func_registry_module, "initialize_registry", initialize_registry
+ )
+ monkeypatch.setattr(
+ ZMQExecutionServer, "_cleanup_compiled_artifacts", lambda self: None
+ )
+ monkeypatch.setattr(
+ ZMQExecutionServer,
+ "_execute_with_orchestrator",
+ lambda self, context: context,
+ )
+ request_payload = ZMQExecutionRequestPayload(
+ identity=ZMQExecutionIdentity(plate_id="/tmp/plate"),
+ pipeline_code=(
+ "from openhcs.codex_virtual.filters import noop\n"
+ "from openhcs.core.config import PipelineConfig\n"
+ "pipeline_config = PipelineConfig()\n"
+ "pipeline_steps = []\n"
+ ),
+ config_transport=ZMQExecutionConfigTransport(
+ config_code=(
+ "from openhcs.core.config import GlobalPipelineConfig\n"
+ "config = GlobalPipelineConfig()\n"
+ ),
+ ),
+ compile_control=ZMQExecutionCompileControl(),
+ )
+
+ context = ZMQExecutionServer()._execute_pipeline("exec-1", request_payload)
+
+ assert initialized == ["registry"]
+ assert context.pipeline_steps == []
+
+
def test_zmq_server_forwards_parent_execution_progress_without_worker_claim() -> None:
server = object.__new__(ZMQExecutionServer)
server._worker_assignments_by_execution = {
diff --git a/tests/unit/test_zmq_execution_server_process.py b/tests/unit/test_zmq_execution_server_process.py
index 2defd6d859..a3daefb76d 100644
--- a/tests/unit/test_zmq_execution_server_process.py
+++ b/tests/unit/test_zmq_execution_server_process.py
@@ -85,7 +85,7 @@ def current(cls, *, detached=False):
def test_execution_server_launcher_advertises_ready_after_start(monkeypatch) -> None:
- """The launcher does not claim readiness before capabilities and sockets start."""
+ """The endpoint becomes ready before on-demand catalog preparation."""
events: list[str] = []
@@ -115,7 +115,7 @@ def log_info(message, *_args) -> None:
server_runner=serve_forever,
)
- assert events == ["construct", "prepare_runtime", "start", "ready", "serve"]
+ assert events == ["construct", "start", "ready", "serve"]
def test_execution_server_launcher_projects_endpoint_overrides_into_config(