From 4845023949d3e1fb7fd5a855207cfd9e4a131a6e Mon Sep 17 00:00:00 2001 From: Leszek Grzanka Date: Fri, 3 Jan 2025 18:01:04 +0100 Subject: [PATCH 1/8] Fix results label in simulation Related to #1927 --- For more details, open the [Copilot Workspace session](https://copilot-workspace.githubnext.com/yaptide/ui/issues/1927?shareId=XXXX-XXXX-XXXX-XXXX). --- src/services/ShSimulatorService.tsx | 31 ++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/src/services/ShSimulatorService.tsx b/src/services/ShSimulatorService.tsx index 221ec869..2ee23c78 100644 --- a/src/services/ShSimulatorService.tsx +++ b/src/services/ShSimulatorService.tsx @@ -410,17 +410,30 @@ const ShSimulation = ({ children }: GenericContextProviderProps) => { const jobInputs = await getJobInputs(info, signal, cache); - const refsInResults = - jobInputs?.input.inputJson && - recreateRefsInResults(jobInputs.input.inputJson, estimator); + if (jobInputs?.input.inputJson) { + const inputJsonForThisEstimator = { ...jobInputs.input.inputJson }; + inputJsonForThisEstimator.scoringManager.outputs = inputJsonForThisEstimator.scoringManager.outputs.filter( + output => output.name === estimatorName + ); - const data: SpecificEstimator = { - jobId, - estimators: refsInResults ?? estimator, - message: response.message - }; + const refsInResults = recreateRefsInResults(inputJsonForThisEstimator, estimator); - resolve(data); + const data: SpecificEstimator = { + jobId, + estimators: refsInResults ?? estimator, + message: response.message + }; + + resolve(data); + } else { + const data: SpecificEstimator = { + jobId, + estimators: estimator, + message: response.message + }; + + resolve(data); + } }, cacheKey, beforeCacheWrite From 73dd0e0a719387e4594d7693943e1b6ea587b50a Mon Sep 17 00:00:00 2001 From: Leszek Grzanka Date: Fri, 3 Jan 2025 18:33:30 +0100 Subject: [PATCH 2/8] Modify `getEstimatorsPages` callback to log `inputJsonForThisEstimator` and its `outputs` field * Add console logs for `inputJsonForThisEstimator` and its `outputs` field --- src/services/ShSimulatorService.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/services/ShSimulatorService.tsx b/src/services/ShSimulatorService.tsx index 2ee23c78..b340fefa 100644 --- a/src/services/ShSimulatorService.tsx +++ b/src/services/ShSimulatorService.tsx @@ -416,6 +416,9 @@ const ShSimulation = ({ children }: GenericContextProviderProps) => { output => output.name === estimatorName ); + console.log('inputJsonForThisEstimator:', inputJsonForThisEstimator); + console.log('Outputs:', inputJsonForThisEstimator.scoringManager.outputs); + const refsInResults = recreateRefsInResults(inputJsonForThisEstimator, estimator); const data: SpecificEstimator = { From e6cd9aca4c081b9ba9cba906f638219072888fd4 Mon Sep 17 00:00:00 2001 From: Leszek Grzanka Date: Fri, 3 Jan 2025 18:40:03 +0100 Subject: [PATCH 3/8] Modify `getEstimatorsPages` callback to handle `inputJson` and `outputs` field * **Recreate references functions** - Document `recreateRefsInResults`, `recreateRefToFilters`, and `recreateRefToScoringManagerOutputs` functions * **Error message** - Fix typo in error message from "esitamtors" to "estimators" * **Input JSON handling** - Make a copy of `jobInputs.input.inputJson` and assign it to `inputJsonForThisEstimator` - Ensure `inputJsonForThisEstimator` contains a field called `outputs` - Pass a single-element list as `outputs` to `recreateRefsInResults` - Dump `inputJsonForThisEstimator` to the console, particularly its `outputs` field --- src/services/ShSimulatorService.tsx | 38 +++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/src/services/ShSimulatorService.tsx b/src/services/ShSimulatorService.tsx index b340fefa..a3a5a8b5 100644 --- a/src/services/ShSimulatorService.tsx +++ b/src/services/ShSimulatorService.tsx @@ -90,6 +90,12 @@ export interface RestSimulationContext { ) => Promise; } +/** + * Recreates references to scoring manager outputs in the estimators. + * @param estimators - The list of estimators. + * @param scoringManagerJSON - The scoring manager JSON. + * @returns The estimators with updated scoring output references. + */ const recreateRefToScoringManagerOutputs = ( estimators: Estimator[], scoringManagerJSON: ScoringManagerJSON @@ -101,6 +107,12 @@ const recreateRefToScoringManagerOutputs = ( return estimators; }; +/** + * Recreates references to filters in the estimators. + * @param estimators - The list of estimators. + * @param FiltersJSON - The list of filter JSON objects. + * @returns The estimators with updated filter references. + */ const recreateRefToFilters = (estimators: Estimator[], FiltersJSON: FilterJSON[]): Estimator[] => { estimators.forEach(estimator => { const { pages, scoringOutputJsonRef } = estimator; @@ -115,9 +127,16 @@ const recreateRefToFilters = (estimators: Estimator[], FiltersJSON: FilterJSON[] return estimators; }; +/** + * Recreates references in the simulation results. + * @param inputJson - The input JSON containing the editor data. + * @param estimators - The list of estimators. + * @returns The estimators with updated references. + * @throws {Error} If no editor data or estimators data is provided. + */ export const recreateRefsInResults = (inputJson: EditorJson, estimators: Estimator[]) => { if (!inputJson) throw new Error('No editor data'); - if (!estimators) throw new Error('No esitamtors data'); + if (!estimators) throw new Error('No estimators data'); const { scoringManager }: EditorJson = inputJson; @@ -412,14 +431,17 @@ const ShSimulation = ({ children }: GenericContextProviderProps) => { if (jobInputs?.input.inputJson) { const inputJsonForThisEstimator = { ...jobInputs.input.inputJson }; - inputJsonForThisEstimator.scoringManager.outputs = inputJsonForThisEstimator.scoringManager.outputs.filter( - output => output.name === estimatorName - ); - - console.log('inputJsonForThisEstimator:', inputJsonForThisEstimator); - console.log('Outputs:', inputJsonForThisEstimator.scoringManager.outputs); + inputJsonForThisEstimator.outputs = [ + inputJsonForThisEstimator.outputs.find( + output => output.name === estimatorName + ) + ]; + console.log('inputJsonForThisEstimator:', inputJsonForThisEstimator.outputs); - const refsInResults = recreateRefsInResults(inputJsonForThisEstimator, estimator); + const refsInResults = recreateRefsInResults( + inputJsonForThisEstimator, + estimator + ); const data: SpecificEstimator = { jobId, From bf32ecdbc9701dd9e7f2de3e8d3aec377089f423 Mon Sep 17 00:00:00 2001 From: Leszek Grzanka Date: Fri, 3 Jan 2025 18:45:17 +0100 Subject: [PATCH 4/8] Modify `getEstimatorsPages` callback to handle `inputJson` copy and pass filtered outputs * Make a copy of `jobInputs.input.inputJson` and assign it to `inputJsonForThisEstimator` * Ensure `inputJsonForThisEstimator` contains a field called `outputs` * Pass a single-element list as `outputs` to `recreateRefsInResults` * Update `data` object and `resolve` logic to handle the new `inputJsonForThisEstimator` --- src/services/ShSimulatorService.tsx | 35 +++++------------------------ 1 file changed, 5 insertions(+), 30 deletions(-) diff --git a/src/services/ShSimulatorService.tsx b/src/services/ShSimulatorService.tsx index a3a5a8b5..2ee23c78 100644 --- a/src/services/ShSimulatorService.tsx +++ b/src/services/ShSimulatorService.tsx @@ -90,12 +90,6 @@ export interface RestSimulationContext { ) => Promise; } -/** - * Recreates references to scoring manager outputs in the estimators. - * @param estimators - The list of estimators. - * @param scoringManagerJSON - The scoring manager JSON. - * @returns The estimators with updated scoring output references. - */ const recreateRefToScoringManagerOutputs = ( estimators: Estimator[], scoringManagerJSON: ScoringManagerJSON @@ -107,12 +101,6 @@ const recreateRefToScoringManagerOutputs = ( return estimators; }; -/** - * Recreates references to filters in the estimators. - * @param estimators - The list of estimators. - * @param FiltersJSON - The list of filter JSON objects. - * @returns The estimators with updated filter references. - */ const recreateRefToFilters = (estimators: Estimator[], FiltersJSON: FilterJSON[]): Estimator[] => { estimators.forEach(estimator => { const { pages, scoringOutputJsonRef } = estimator; @@ -127,16 +115,9 @@ const recreateRefToFilters = (estimators: Estimator[], FiltersJSON: FilterJSON[] return estimators; }; -/** - * Recreates references in the simulation results. - * @param inputJson - The input JSON containing the editor data. - * @param estimators - The list of estimators. - * @returns The estimators with updated references. - * @throws {Error} If no editor data or estimators data is provided. - */ export const recreateRefsInResults = (inputJson: EditorJson, estimators: Estimator[]) => { if (!inputJson) throw new Error('No editor data'); - if (!estimators) throw new Error('No estimators data'); + if (!estimators) throw new Error('No esitamtors data'); const { scoringManager }: EditorJson = inputJson; @@ -431,18 +412,12 @@ const ShSimulation = ({ children }: GenericContextProviderProps) => { if (jobInputs?.input.inputJson) { const inputJsonForThisEstimator = { ...jobInputs.input.inputJson }; - inputJsonForThisEstimator.outputs = [ - inputJsonForThisEstimator.outputs.find( - output => output.name === estimatorName - ) - ]; - console.log('inputJsonForThisEstimator:', inputJsonForThisEstimator.outputs); - - const refsInResults = recreateRefsInResults( - inputJsonForThisEstimator, - estimator + inputJsonForThisEstimator.scoringManager.outputs = inputJsonForThisEstimator.scoringManager.outputs.filter( + output => output.name === estimatorName ); + const refsInResults = recreateRefsInResults(inputJsonForThisEstimator, estimator); + const data: SpecificEstimator = { jobId, estimators: refsInResults ?? estimator, From 227e886d1effca2a8fbd5cfc1337b6cd3715d24d Mon Sep 17 00:00:00 2001 From: Leszek Grzanka Date: Fri, 3 Jan 2025 20:16:01 +0100 Subject: [PATCH 5/8] Modify `getEstimatorsPages` callback to handle `inputJson` and add logging * Make a copy of `jobInputs.input.inputJson` and assign it to `inputJsonForThisEstimator` * Ensure `inputJsonForThisEstimator` contains a field called `outputs` * Pass a single-element list as `outputs` to `recreateRefsInResults` * Add logging for `inputJsonForThisEstimator` in the console * Add debugging logging to console in `recreateRefToScoringManagerOutputs`, `recreateRefToFilters`, and `recreateRefsInResults` * Add comments explaining code logic in `recreateRefToScoringManagerOutputs`, `recreateRefToFilters`, and `recreateRefsInResults` --- src/services/ShSimulatorService.tsx | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/services/ShSimulatorService.tsx b/src/services/ShSimulatorService.tsx index 2ee23c78..94710b36 100644 --- a/src/services/ShSimulatorService.tsx +++ b/src/services/ShSimulatorService.tsx @@ -94,6 +94,7 @@ const recreateRefToScoringManagerOutputs = ( estimators: Estimator[], scoringManagerJSON: ScoringManagerJSON ): Estimator[] => { + // Iterate through each estimator and set the scoringOutputJsonRef to the corresponding output in scoringManagerJSON estimators.forEach((estimator, index) => { estimator.scoringOutputJsonRef = scoringManagerJSON.outputs[index]; }); @@ -102,6 +103,7 @@ const recreateRefToScoringManagerOutputs = ( }; const recreateRefToFilters = (estimators: Estimator[], FiltersJSON: FilterJSON[]): Estimator[] => { + // Iterate through each estimator and set the filterRef and name for each page estimators.forEach(estimator => { const { pages, scoringOutputJsonRef } = estimator; pages.forEach((page, idx) => { @@ -117,7 +119,7 @@ const recreateRefToFilters = (estimators: Estimator[], FiltersJSON: FilterJSON[] export const recreateRefsInResults = (inputJson: EditorJson, estimators: Estimator[]) => { if (!inputJson) throw new Error('No editor data'); - if (!estimators) throw new Error('No esitamtors data'); + if (!estimators) throw new Error('No estimators data'); const { scoringManager }: EditorJson = inputJson; @@ -412,11 +414,17 @@ const ShSimulation = ({ children }: GenericContextProviderProps) => { if (jobInputs?.input.inputJson) { const inputJsonForThisEstimator = { ...jobInputs.input.inputJson }; - inputJsonForThisEstimator.scoringManager.outputs = inputJsonForThisEstimator.scoringManager.outputs.filter( - output => output.name === estimatorName - ); + inputJsonForThisEstimator.scoringManager.outputs = [ + inputJsonForThisEstimator.scoringManager.outputs.find( + output => output.name === estimatorName + ) + ]; + console.log('inputJsonForThisEstimator:', inputJsonForThisEstimator); - const refsInResults = recreateRefsInResults(inputJsonForThisEstimator, estimator); + const refsInResults = recreateRefsInResults( + inputJsonForThisEstimator, + estimator + ); const data: SpecificEstimator = { jobId, From 900fe9e9ba8b998ae1e9b622c8b4a7604ce067c8 Mon Sep 17 00:00:00 2001 From: Leszek Grzanka Date: Fri, 3 Jan 2025 20:36:11 +0100 Subject: [PATCH 6/8] fixes --- src/services/ShSimulatorService.tsx | 86 ++++++++++++++++++++++++++--- 1 file changed, 77 insertions(+), 9 deletions(-) diff --git a/src/services/ShSimulatorService.tsx b/src/services/ShSimulatorService.tsx index 94710b36..5ab90e77 100644 --- a/src/services/ShSimulatorService.tsx +++ b/src/services/ShSimulatorService.tsx @@ -102,36 +102,101 @@ const recreateRefToScoringManagerOutputs = ( return estimators; }; +/** + * Recreates references between estimators, their pages and filters by linking filter UUIDs with actual filter objects. + * This rebuilds the relationships between estimator pages and their associated filters from the Filter JSON. + * + * @param estimators - Array of estimators containing pages that need filter references rebuilt + * @param FiltersJSON - Array of filter objects that contain the actual filter definitions + * @returns The estimators array with updated filter references for each page + */ const recreateRefToFilters = (estimators: Estimator[], FiltersJSON: FilterJSON[]): Estimator[] => { + console.log('Starting recreateRefToFilters with:', { + estimatorsCount: estimators.length, + filtersCount: FiltersJSON.length + }); + // Iterate through each estimator and set the filterRef and name for each page - estimators.forEach(estimator => { + estimators.forEach((estimator, estimatorIndex) => { + console.log(`Processing estimator ${estimatorIndex}:`, { + name: estimator.name, + pageCount: estimator.pages.length + }); + const { pages, scoringOutputJsonRef } = estimator; + pages.forEach((page, idx) => { + console.log(`Processing page ${idx} for estimator ${estimator.name}`); + const quantity = scoringOutputJsonRef?.quantities[idx]; + console.log('Found quantity:', quantity); + const filter = FiltersJSON.find(o => o.uuid === quantity?.filter); + console.log('Matched filter:', { + filterUUID: quantity?.filter, + foundFilter: filter?.uuid + }); + page.filterRef = filter; page.name = quantity?.name; + + console.log('Updated page:', { + pageName: page.name, + hasFilter: !!page.filterRef + }); }); }); + console.log('Completed recreateRefToFilters, returning estimators with updated filter refs'); + return estimators; }; +/** + * Recreates references in simulation results by linking estimator data with scoring manager outputs and filters + * from the editor JSON. + * + * @param inputJson - The editor JSON containing simulation configuration and scoring manager data + * @param estimators - Array of estimators containing simulation results + * @returns Estimators with updated references to scoring manager outputs and filters + * @throws Error if inputJson or estimators are undefined + */ export const recreateRefsInResults = (inputJson: EditorJson, estimators: Estimator[]) => { - if (!inputJson) throw new Error('No editor data'); - if (!estimators) throw new Error('No estimators data'); + console.log('Starting recreateRefsInResults with:', { + inputJson, + estimators + }); + + if (!inputJson) { + console.error('No editor data provided to recreateRefsInResults'); + + throw new Error('No editor data'); + } + + if (!estimators) { + console.error('No estimators data provided to recreateRefsInResults'); + + throw new Error('No estimators data'); + } const { scoringManager }: EditorJson = inputJson; + console.log('Extracted scoringManager:', scoringManager); const estimatorsWithScoringManagerOutputs = recreateRefToScoringManagerOutputs( estimators, scoringManager ); + console.log( + 'Results after recreateRefToScoringManagerOutputs:', + estimatorsWithScoringManagerOutputs + ); + const estimatorsWithFixedFilters = recreateRefToFilters( estimatorsWithScoringManagerOutputs, scoringManager.filters ); + console.log('Results after recreateRefToFilters:', estimatorsWithFixedFilters); return estimatorsWithFixedFilters; }; @@ -413,12 +478,15 @@ const ShSimulation = ({ children }: GenericContextProviderProps) => { const jobInputs = await getJobInputs(info, signal, cache); if (jobInputs?.input.inputJson) { - const inputJsonForThisEstimator = { ...jobInputs.input.inputJson }; - inputJsonForThisEstimator.scoringManager.outputs = [ - inputJsonForThisEstimator.scoringManager.outputs.find( - output => output.name === estimatorName - ) - ]; + const inputJsonForThisEstimator = { + ...jobInputs.input.inputJson, + scoringManager: { + ...jobInputs.input.inputJson.scoringManager, + outputs: jobInputs.input.inputJson.scoringManager.outputs.filter( + output => output.name === estimatorName + ) + } + }; console.log('inputJsonForThisEstimator:', inputJsonForThisEstimator); const refsInResults = recreateRefsInResults( From eb3ba009de1848e9d18f1db1c2dfe9c539d9fc79 Mon Sep 17 00:00:00 2001 From: Leszek Grzanka Date: Fri, 3 Jan 2025 20:43:45 +0100 Subject: [PATCH 7/8] cleaning --- src/services/ShSimulatorService.tsx | 64 +++++++++-------------------- 1 file changed, 20 insertions(+), 44 deletions(-) diff --git a/src/services/ShSimulatorService.tsx b/src/services/ShSimulatorService.tsx index 5ab90e77..773acc6f 100644 --- a/src/services/ShSimulatorService.tsx +++ b/src/services/ShSimulatorService.tsx @@ -32,7 +32,6 @@ import { ResponseGetEstimatorPageResult, ResponseGetJobInputs, ResponseGetJobLogs, - ResponseGetJobResult, ResponseGetJobResults, ResponseGetJobStatus, ResponseGetPageContents, @@ -90,6 +89,19 @@ export interface RestSimulationContext { ) => Promise; } +/** + * Rebuilds the references between estimators and their corresponding scoring manager outputs. + * Each estimator is linked to an output in the scoring manager JSON by matching array indices. + * The scoringManagerJSON.outputs array length should match the number of estimators - if there are + * fewer outputs than estimators, the extra estimators will have undefined scoringOutputJsonRef. + * If there are more outputs than estimators, the extra outputs will be ignored. + * + * @param estimators - Array of estimators that need scoring manager output references rebuilt + * @param scoringManagerJSON - The scoring manager JSON containing output definitions. The outputs array + * should ideally have the same length as the estimators array to ensure + * all estimators get valid output references. + * @returns The estimators array with updated scoring output references for each estimator + */ const recreateRefToScoringManagerOutputs = ( estimators: Estimator[], scoringManagerJSON: ScoringManagerJSON @@ -111,50 +123,29 @@ const recreateRefToScoringManagerOutputs = ( * @returns The estimators array with updated filter references for each page */ const recreateRefToFilters = (estimators: Estimator[], FiltersJSON: FilterJSON[]): Estimator[] => { - console.log('Starting recreateRefToFilters with:', { - estimatorsCount: estimators.length, - filtersCount: FiltersJSON.length - }); - // Iterate through each estimator and set the filterRef and name for each page estimators.forEach((estimator, estimatorIndex) => { - console.log(`Processing estimator ${estimatorIndex}:`, { - name: estimator.name, - pageCount: estimator.pages.length - }); - const { pages, scoringOutputJsonRef } = estimator; - pages.forEach((page, idx) => { - console.log(`Processing page ${idx} for estimator ${estimator.name}`); - const quantity = scoringOutputJsonRef?.quantities[idx]; - console.log('Found quantity:', quantity); - const filter = FiltersJSON.find(o => o.uuid === quantity?.filter); - console.log('Matched filter:', { - filterUUID: quantity?.filter, - foundFilter: filter?.uuid - }); - page.filterRef = filter; page.name = quantity?.name; - - console.log('Updated page:', { - pageName: page.name, - hasFilter: !!page.filterRef - }); }); }); - console.log('Completed recreateRefToFilters, returning estimators with updated filter refs'); - return estimators; }; /** * Recreates references in simulation results by linking estimator data with scoring manager outputs and filters - * from the editor JSON. + * from the editor JSON. This function expects specific array length relationships to work properly: + * + * 1. The scoringManager.outputs array length should match the number of estimators, otherwise: + * - If fewer outputs than estimators: excess estimators will have undefined scoringOutputJsonRef + * - If more outputs than estimators: extra outputs are ignored + * 2. Within each estimator, the number of pages should match the number of quantities in the + * corresponding scoring manager output for proper filter assignment * * @param inputJson - The editor JSON containing simulation configuration and scoring manager data * @param estimators - Array of estimators containing simulation results @@ -162,11 +153,6 @@ const recreateRefToFilters = (estimators: Estimator[], FiltersJSON: FilterJSON[] * @throws Error if inputJson or estimators are undefined */ export const recreateRefsInResults = (inputJson: EditorJson, estimators: Estimator[]) => { - console.log('Starting recreateRefsInResults with:', { - inputJson, - estimators - }); - if (!inputJson) { console.error('No editor data provided to recreateRefsInResults'); @@ -180,23 +166,15 @@ export const recreateRefsInResults = (inputJson: EditorJson, estimators: Estimat } const { scoringManager }: EditorJson = inputJson; - console.log('Extracted scoringManager:', scoringManager); - const estimatorsWithScoringManagerOutputs = recreateRefToScoringManagerOutputs( estimators, scoringManager ); - console.log( - 'Results after recreateRefToScoringManagerOutputs:', - estimatorsWithScoringManagerOutputs - ); - const estimatorsWithFixedFilters = recreateRefToFilters( estimatorsWithScoringManagerOutputs, scoringManager.filters ); - console.log('Results after recreateRefToFilters:', estimatorsWithFixedFilters); return estimatorsWithFixedFilters; }; @@ -487,7 +465,6 @@ const ShSimulation = ({ children }: GenericContextProviderProps) => { ) } }; - console.log('inputJsonForThisEstimator:', inputJsonForThisEstimator); const refsInResults = recreateRefsInResults( inputJsonForThisEstimator, @@ -598,7 +575,6 @@ const ShSimulation = ({ children }: GenericContextProviderProps) => { currentJobStatusData[StatusState.FAILED](data) || currentJobStatusData[StatusState.CANCELED](data) ) { - console.log(data.message); statusDataCache.set(data.jobId, data, beforeCacheWrite); return data; From fb49c3937d22ee8c326ea5d58baf68083d5c69dd Mon Sep 17 00:00:00 2001 From: Leszek Grzanka Date: Fri, 3 Jan 2025 20:45:42 +0100 Subject: [PATCH 8/8] more comments --- src/services/ShSimulatorService.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/services/ShSimulatorService.tsx b/src/services/ShSimulatorService.tsx index 773acc6f..360f03da 100644 --- a/src/services/ShSimulatorService.tsx +++ b/src/services/ShSimulatorService.tsx @@ -455,6 +455,7 @@ const ShSimulation = ({ children }: GenericContextProviderProps) => { const jobInputs = await getJobInputs(info, signal, cache); + // if editor project data (with filter definions etc) is available, recreate references in results if (jobInputs?.input.inputJson) { const inputJsonForThisEstimator = { ...jobInputs.input.inputJson, @@ -479,6 +480,8 @@ const ShSimulation = ({ children }: GenericContextProviderProps) => { resolve(data); } else { + // if editor project data is not available (i.e. running from user uploaded files), + // return the results without recreating references const data: SpecificEstimator = { jobId, estimators: estimator,