From 9c8d8f016c3b8c7726a120569a77cfd0055b74db Mon Sep 17 00:00:00 2001 From: Dan Wolfson Date: Tue, 13 Oct 2026 16:54:20 -0500 Subject: [PATCH 1/6] docs(issues): log ISSUE-148 (AssetMaker action queries default to IN_PROGRESS, dropping journal entries) Reported by the egeria-workspaces-fs session. Signed-off-by: Dan Wolfson --- PYEGERIA_ISSUES.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/PYEGERIA_ISSUES.md b/PYEGERIA_ISSUES.md index 9e27dce0..f83d2c5d 100644 --- a/PYEGERIA_ISSUES.md +++ b/PYEGERIA_ISSUES.md @@ -151,6 +151,7 @@ content was changed. The numbered section list above describes the **At a glance** — 7 open pyegeria items, 7 awaiting re-test, 7 open Egeria Server issues. **Open pyegeria items** +- ISSUE-148: AssetMaker action/process queries default `activity_status_list` to `["IN_PROGRESS"]`, which silently drops JournalEntries and any other Action with no activity status - ISSUE-146: Deleting a journal entry fails with OMAG-REPOSITORY-HANDLER-400-008, and pyegeria's `remove_note` reaches the delete only through the generic Asset Maker service - ISSUE-140: The executor charts any dict with two or more top-level numbers, regardless of the result's state - ISSUE-139: The executor renders no result envelope, and the Vega bar chart has no subtitle, so a not-established result has nowhere to say so on a chart @@ -188,6 +189,21 @@ into the entry now, so it isn't rediscovered from scratch later. --- +### ISSUE-148: AssetMaker action/process queries default `activity_status_list` to `["IN_PROGRESS"]`, which silently drops JournalEntries and any other Action with no activity status + +**Layer:** pyegeria (`pyegeria/omvs/asset_maker.py`) · **Status:** open, logged only (no fix without the owner's go-ahead) · **Found:** 2026-10-13 by the egeria-workspaces-fs session (Resource Locator) on pyegeria 6.2.0 in quickstart-pyegeria-web. + +**What:** for resource `4e53842e`, which has an Actions link to JournalEntry `8bec72e4` (see ISSUE-146), `get_actions_for_sponsor` with the default returns 0 elements. Passing `activity_status_list=None` or `[]` returns 1. There is no error and no warning. A JournalEntry has no activity status, so an `IN_PROGRESS` filter can never match it. The same goes for completed, waiting or failed actions. + +**Where:** 7 public methods default to `["IN_PROGRESS"]`, as do their `_async_` versions: +`find_processes`, `get_processes_by_category`, `get_action_targets`, `get_actions_for_action_target`, `get_assigned_actions`, `get_actions_for_sponsor` and `get_actions_for_requester`. All are in `asset_maker.py`, around lines 3881-5210. + +**Why it matters:** a caller who doesn't know about the filter gets "No elements found", and that looks the same as "this element has no actions". The absence is reported as an answer. + +**Candidate fix (needs a decision):** default to `None`, so no status filter is applied and the server returns everything, and let callers ask for `["IN_PROGRESS"]` explicitly. This changes behaviour for existing callers that relied on the filter (for example, To-Do views that expect only open work), so check the callers in egeria-workspaces-fs, trellis and `commands/` first. Then add a micro-test that captures the request body for each method. + +--- + ### ISSUE-146: Deleting a journal entry fails with OMAG-REPOSITORY-HANDLER-400-008, and pyegeria's `remove_note` reaches the delete only through the generic Asset Maker service **Layer:** Egeria Server (pyegeria clean-up) · **Status:** open · **Found:** 2026-10-13, reported by the egeria-workspaces-fs Resource Browser session from a live private-journal test. From 283d3f8a4769943c3761beccea28284187eb6fed Mon Sep 17 00:00:00 2001 From: Dan Wolfson Date: Tue, 13 Oct 2026 17:00:30 -0500 Subject: [PATCH 2/6] fix(asset-maker): default activity_status_list to None (no filter) (ISSUE-148) Seven AssetMaker action/process queries (find_processes, get_processes_by_category, get_action_targets, get_actions_for_action_target, get_assigned_actions, get_actions_for_sponsor, get_actions_for_requester) defaulted to ["IN_PROGRESS"], which silently dropped journal entries and every finished action. _async_find_processes defaulted to [] while its sync wrapper used ["IN_PROGRESS"], so the two disagreed. All 14 signatures now default to None. Behaviour change: callers that want only in-progress actions must pass ["IN_PROGRESS"] explicitly. No known caller relies on the old default (checked with the egeria-workspaces-fs and trellis sessions). Noted for the 6.2.3 release notes in BACKLOG.md. Signed-off-by: Dan Wolfson --- BACKLOG.md | 1 + PYEGERIA_ISSUES.md | 40 +++++++----- pyegeria/omvs/asset_maker.py | 56 ++++++++--------- .../test_issue_148_activity_status_default.py | 61 +++++++++++++++++++ 4 files changed, 115 insertions(+), 43 deletions(-) create mode 100644 tests/micro-tests/test_issue_148_activity_status_default.py diff --git a/BACKLOG.md b/BACKLOG.md index d419f13f..0efc7dec 100644 --- a/BACKLOG.md +++ b/BACKLOG.md @@ -16,6 +16,7 @@ Once the Egeria release with the delete fixes is published and the local quickst 2. **Other delete issues** to re-check at the same time: ISSUE-117 (Memento cascade delete), ISSUE-125 (`deleteEnumDef`) and ISSUE-132 (`cascadedDelete` field name). Also ISSUE-147, the valid-metadata clears: re-run the ISSUE-147 sequence (setup then clear for a value, a map name and a map value on a made-up property). Expect no 400-011 error after a successful clear, and expect the map value to actually be removed. 3. Update each `PYEGERIA_ISSUES.md` entry with the result, then do the held 6.2.3 release. The owner wants outstanding issues fixed before releasing. + **The 6.2.3 release notes must list this behaviour change:** ISSUE-148. `AssetMaker.find_processes`, `get_processes_by_category`, `get_action_targets`, `get_actions_for_action_target`, `get_assigned_actions`, `get_actions_for_sponsor` and `get_actions_for_requester` now default `activity_status_list` to `None` (no filter) instead of `["IN_PROGRESS"]`. A caller that relied on getting only in-progress actions by default now also gets completed, cancelled and status-less actions (e.g. journal entries), so it should pass `["IN_PROGRESS"]` explicitly. --- diff --git a/PYEGERIA_ISSUES.md b/PYEGERIA_ISSUES.md index f83d2c5d..e9bfa074 100644 --- a/PYEGERIA_ISSUES.md +++ b/PYEGERIA_ISSUES.md @@ -151,7 +151,6 @@ content was changed. The numbered section list above describes the **At a glance** — 7 open pyegeria items, 7 awaiting re-test, 7 open Egeria Server issues. **Open pyegeria items** -- ISSUE-148: AssetMaker action/process queries default `activity_status_list` to `["IN_PROGRESS"]`, which silently drops JournalEntries and any other Action with no activity status - ISSUE-146: Deleting a journal entry fails with OMAG-REPOSITORY-HANDLER-400-008, and pyegeria's `remove_note` reaches the delete only through the generic Asset Maker service - ISSUE-140: The executor charts any dict with two or more top-level numbers, regardless of the result's state - ISSUE-139: The executor renders no result envelope, and the Vega bar chart has no subtitle, so a not-established result has nowhere to say so on a chart @@ -189,20 +188,6 @@ into the entry now, so it isn't rediscovered from scratch later. --- -### ISSUE-148: AssetMaker action/process queries default `activity_status_list` to `["IN_PROGRESS"]`, which silently drops JournalEntries and any other Action with no activity status - -**Layer:** pyegeria (`pyegeria/omvs/asset_maker.py`) · **Status:** open, logged only (no fix without the owner's go-ahead) · **Found:** 2026-10-13 by the egeria-workspaces-fs session (Resource Locator) on pyegeria 6.2.0 in quickstart-pyegeria-web. - -**What:** for resource `4e53842e`, which has an Actions link to JournalEntry `8bec72e4` (see ISSUE-146), `get_actions_for_sponsor` with the default returns 0 elements. Passing `activity_status_list=None` or `[]` returns 1. There is no error and no warning. A JournalEntry has no activity status, so an `IN_PROGRESS` filter can never match it. The same goes for completed, waiting or failed actions. - -**Where:** 7 public methods default to `["IN_PROGRESS"]`, as do their `_async_` versions: -`find_processes`, `get_processes_by_category`, `get_action_targets`, `get_actions_for_action_target`, `get_assigned_actions`, `get_actions_for_sponsor` and `get_actions_for_requester`. All are in `asset_maker.py`, around lines 3881-5210. - -**Why it matters:** a caller who doesn't know about the filter gets "No elements found", and that looks the same as "this element has no actions". The absence is reported as an answer. - -**Candidate fix (needs a decision):** default to `None`, so no status filter is applied and the server returns everything, and let callers ask for `["IN_PROGRESS"]` explicitly. This changes behaviour for existing callers that relied on the filter (for example, To-Do views that expect only open work), so check the callers in egeria-workspaces-fs, trellis and `commands/` first. Then add a micro-test that captures the request body for each method. - ---- ### ISSUE-146: Deleting a journal entry fails with OMAG-REPOSITORY-HANDLER-400-008, and pyegeria's `remove_note` reaches the delete only through the generic Asset Maker service @@ -1578,6 +1563,31 @@ Sorted newest-first by `ISSUE-#` (2026-10-12). ISSUE-91 has two entries --- +### ISSUE-148: AssetMaker action/process queries default `activity_status_list` to `["IN_PROGRESS"]`, which silently drops JournalEntries and any other Action with no activity status + +**Layer:** pyegeria (`pyegeria/omvs/asset_maker.py`) · **Status:** fixed 2026-10-13 · **Found:** 2026-10-13 by the egeria-workspaces-fs session (Resource Locator) on pyegeria 6.2.0 in quickstart-pyegeria-web. + +**What:** for resource `4e53842e`, which has an Actions link to JournalEntry `8bec72e4` (see ISSUE-146), `get_actions_for_sponsor` with the default returns 0 elements. Passing `activity_status_list=None` or `[]` returns 1. There is no error and no warning. A JournalEntry has no activity status, so an `IN_PROGRESS` filter can never match it. The same goes for completed, waiting or failed actions. + +**Where:** 7 public methods default to `["IN_PROGRESS"]`, as do their `_async_` versions: +`find_processes`, `get_processes_by_category`, `get_action_targets`, `get_actions_for_action_target`, `get_assigned_actions`, `get_actions_for_sponsor` and `get_actions_for_requester`. All are in `asset_maker.py`, around lines 3881-5210. + +**Why it matters:** a caller who doesn't know about the filter gets "No elements found", and that looks the same as "this element has no actions". The absence is reported as an answer. + +**Candidate fix (needs a decision):** default to `None`, so no status filter is applied and the server returns everything, and let callers ask for `["IN_PROGRESS"]` explicitly. This changes behaviour for existing callers that relied on the filter (for example, To-Do views that expect only open work), so check the callers in egeria-workspaces-fs, trellis and `commands/` first. Then add a micro-test that captures the request body for each method. + +**Fixed 2026-10-13 (owner's go-ahead, after all four live sessions confirmed no caller relies on the default):** +all 14 signatures (7 sync, 7 async) now take `activity_status_list: Optional[list[str]] = None`, and the +docstrings say "no filter". `_async_find_processes` had defaulted to `[]` while the sync `find_processes` +defaulted to `["IN_PROGRESS"]`, so the same query had returned different results depending on which +version was called. Callers checked: egeria-workspaces-fs `tech_catalog_handler` (passes `[]`) and +`resource_browser_handler` (passes `None`), egeria-python `commands/` (passes its own filter); trellis has none. +**This is a behaviour change, so it must go in the 6.2.3 release notes** (see BACKLOG.md). Test: +`tests/micro-tests/test_issue_148_activity_status_default.py`, which checks that the default sends no +`activityStatusList` and that an explicit filter is still sent. + +--- + ### ISSUE-145: Dr.Egeria sends `agreementType` and other `agreement*` fields that Egeria's `AgreementProperties` does not have **Layer:** Dr.Egeria · **Status:** fixed 2026-10-13 · **Found:** 2026-10-13, during the ISSUE-144 status-field sweep. diff --git a/pyegeria/omvs/asset_maker.py b/pyegeria/omvs/asset_maker.py index 769ae0b3..f1f0fb18 100644 --- a/pyegeria/omvs/asset_maker.py +++ b/pyegeria/omvs/asset_maker.py @@ -3781,7 +3781,7 @@ def detach_software_capability_from_asset( async def _async_find_processes( self, search_string: str = "*", - activity_status_list: list[str] = [], + activity_status_list: Optional[list[str]] = None, starts_with: bool = True, ends_with: bool = False, ignore_case: bool = True, @@ -3814,7 +3814,7 @@ async def _async_find_processes( ---------- search_string: str, default = "*" - search string for process properties - activity_status_list: list[str], default = [] + activity_status_list: list[str], default = None (no filter: every activity status, including none) - optional activity status list to filter by starts_with: bool, default = True ends_with: bool, default = False @@ -3881,7 +3881,7 @@ async def _async_find_processes( def find_processes( self, search_string: str = "*", - activity_status_list: list[str] = ["IN_PROGRESS"], + activity_status_list: Optional[list[str]] = None, starts_with: bool = True, ends_with: bool = False, ignore_case: bool = True, @@ -3914,7 +3914,7 @@ def find_processes( ---------- search_string: str, default = "*" - the search string to use to find matching processes - activity_status_list: list[str], default = ["IN_PROGRESS"] + activity_status_list: list[str], default = None (no filter: every activity status, including none) - optional activity status list to filter by starts_with: bool, default = True - if True, the search string must match the start of the property value @@ -3988,7 +3988,7 @@ def find_processes( async def _async_get_processes_by_category( self, category: str, - activity_status_list: list[str] = ["IN_PROGRESS"], + activity_status_list: Optional[list[str]] = None, graph_query_depth: int = 3, start_from: int = 0, page_size: int = 0, @@ -4003,7 +4003,7 @@ async def _async_get_processes_by_category( Parameters ---------- category: str - activity_status_list: list[str], default = ["IN_PROGRESS"] + activity_status_list: list[str], default = None (no filter: every activity status, including none) graph_query_depth: int, default = 3 - depth for relationship traversal start_from: int, default = 0 @@ -4048,7 +4048,7 @@ async def _async_get_processes_by_category( def get_processes_by_category( self, category: str, - activity_status_list: list[str] = ["IN_PROGRESS"], + activity_status_list: Optional[list[str]] = None, graph_query_depth: int = 3, start_from: int = 0, page_size: int = 0, @@ -4064,7 +4064,7 @@ def get_processes_by_category( ---------- category: str - category name to filter by - activity_status_list: list[str], default = ["IN_PROGRESS"] + activity_status_list: list[str], default = None (no filter: every activity status, including none) - optional activity status list to filter by graph_query_depth: int, default = 3 - depth for relationship traversal @@ -4526,7 +4526,7 @@ def get_action_target( async def _async_get_action_targets( self, action_guid: str, - activity_status_list: list[str] = ["IN_PROGRESS"], + activity_status_list: Optional[list[str]] = None, graph_query_depth: int = 3, start_from: int = 0, page_size: int = 0, @@ -4544,7 +4544,7 @@ async def _async_get_action_targets( Parameters ---------- action_guid: str - activity_status_list: list[str], default = ["IN_PROGRESS"] + activity_status_list: list[str], default = None (no filter: every activity status, including none) graph_query_depth: int, default = 3 - depth for relationship traversal body: dict | ActivityStatusRequestBody, optional @@ -4577,7 +4577,7 @@ async def _async_get_action_targets( def get_action_targets( self, action_guid: str, - activity_status_list: list[str] = ["IN_PROGRESS"], + activity_status_list: Optional[list[str]] = None, graph_query_depth: int = 3, start_from: int = 0, page_size: int = 0, @@ -4595,7 +4595,7 @@ def get_action_targets( Parameters ---------- action_guid: str - activity_status_list: list[str], default = ["IN_PROGRESS"] + activity_status_list: list[str], default = None (no filter: every activity status, including none) graph_query_depth: int, default = 3 - depth for relationship traversal start_from: int, default = 0 @@ -4641,7 +4641,7 @@ def get_action_targets( async def _async_get_actions_for_action_target( self, metadata_element_guid: str, - activity_status_list: list[str] = ["IN_PROGRESS"], + activity_status_list: Optional[list[str]] = None, graph_query_depth: int = 3, start_from: int = 0, page_size: int = 0, @@ -4659,7 +4659,7 @@ async def _async_get_actions_for_action_target( Parameters ---------- metadata_element_guid: str - activity_status_list: list[str], default = ["IN_PROGRESS"] + activity_status_list: list[str], default = None (no filter: every activity status, including none) graph_query_depth: int, default = 3 - depth for relationship traversal body: dict | ActivityStatusRequestBody, optional @@ -4692,7 +4692,7 @@ async def _async_get_actions_for_action_target( def get_actions_for_action_target( self, metadata_element_guid: str, - activity_status_list: list[str] = ["IN_PROGRESS"], + activity_status_list: Optional[list[str]] = None, graph_query_depth: int = 3, start_from: int = 0, page_size: int = 0, @@ -4710,7 +4710,7 @@ def get_actions_for_action_target( Parameters ---------- metadata_element_guid: str - activity_status_list: list[str], default = ["IN_PROGRESS"] + activity_status_list: list[str], default = None (no filter: every activity status, including none) graph_query_depth: int, default = 3 - depth for relationship traversal start_from: int, default = 0 @@ -4925,7 +4925,7 @@ def unassign_action( async def _async_get_assigned_actions( self, actor_guid: str, - activity_status_list: list[str] = ["IN_PROGRESS"], + activity_status_list: Optional[list[str]] = None, graph_query_depth: int = 3, start_from: int = 0, page_size: int = 0, @@ -4943,7 +4943,7 @@ async def _async_get_assigned_actions( Parameters ---------- actor_guid: str - activity_status_list: list[str], default = ["IN_PROGRESS"] + activity_status_list: list[str], default = None (no filter: every activity status, including none) graph_query_depth: int, default = 3 - depth for relationship traversal body: dict | ActivityStatusRequestBody, optional @@ -4976,7 +4976,7 @@ async def _async_get_assigned_actions( def get_assigned_actions( self, actor_guid: str, - activity_status_list: list[str] = ["IN_PROGRESS"], + activity_status_list: Optional[list[str]] = None, graph_query_depth: int = 3, start_from: int = 0, page_size: int = 0, @@ -4994,7 +4994,7 @@ def get_assigned_actions( Parameters ---------- actor_guid: str - activity_status_list: list[str], default = ["IN_PROGRESS"] + activity_status_list: list[str], default = None (no filter: every activity status, including none) graph_query_depth: int, default = 3 - depth for relationship traversal start_from: int, default = 0 @@ -5040,7 +5040,7 @@ def get_assigned_actions( async def _async_get_actions_for_sponsor( self, metadata_element_guid: str, - activity_status_list: list[str] = ["IN_PROGRESS"], + activity_status_list: Optional[list[str]] = None, graph_query_depth: int = 3, start_from: int = 0, page_size: int = 0, @@ -5058,7 +5058,7 @@ async def _async_get_actions_for_sponsor( Parameters ---------- metadata_element_guid: str - activity_status_list: list[str], default = ["IN_PROGRESS"] + activity_status_list: list[str], default = None (no filter: every activity status, including none) graph_query_depth: int, default = 3 - depth for relationship traversal body: dict | ActivityStatusRequestBody, optional @@ -5091,7 +5091,7 @@ async def _async_get_actions_for_sponsor( def get_actions_for_sponsor( self, metadata_element_guid: str, - activity_status_list: list[str] = ["IN_PROGRESS"], + activity_status_list: Optional[list[str]] = None, graph_query_depth: int = 3, start_from: int = 0, page_size: int = 0, @@ -5109,7 +5109,7 @@ def get_actions_for_sponsor( Parameters ---------- metadata_element_guid: str - activity_status_list: list[str], default = ["IN_PROGRESS"] + activity_status_list: list[str], default = None (no filter: every activity status, including none) graph_query_depth: int, default = 3 - depth for relationship traversal start_from: int, default = 0 @@ -5155,7 +5155,7 @@ def get_actions_for_sponsor( async def _async_get_actions_for_requester( self, metadata_element_guid: str, - activity_status_list: list[str] = ["IN_PROGRESS"], + activity_status_list: Optional[list[str]] = None, graph_query_depth: int = 3, start_from: int = 0, page_size: int = 0, @@ -5173,7 +5173,7 @@ async def _async_get_actions_for_requester( Parameters ---------- metadata_element_guid: str - activity_status_list: list[str], default = ["IN_PROGRESS"] + activity_status_list: list[str], default = None (no filter: every activity status, including none) graph_query_depth: int, default = 3 - depth for relationship traversal body: dict | ActivityStatusRequestBody, optional @@ -5206,7 +5206,7 @@ async def _async_get_actions_for_requester( def get_actions_for_requester( self, metadata_element_guid: str, - activity_status_list: list[str] = ["IN_PROGRESS"], + activity_status_list: Optional[list[str]] = None, graph_query_depth: int = 3, start_from: int = 0, page_size: int = 0, @@ -5224,7 +5224,7 @@ def get_actions_for_requester( Parameters ---------- metadata_element_guid: str - activity_status_list: list[str], default = ["IN_PROGRESS"] + activity_status_list: list[str], default = None (no filter: every activity status, including none) graph_query_depth: int, default = 3 - depth for relationship traversal start_from: int, default = 0 diff --git a/tests/micro-tests/test_issue_148_activity_status_default.py b/tests/micro-tests/test_issue_148_activity_status_default.py new file mode 100644 index 00000000..268583bd --- /dev/null +++ b/tests/micro-tests/test_issue_148_activity_status_default.py @@ -0,0 +1,61 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright Contributors to the ODPi Egeria project. +""" +Regression test for ISSUE-148 (PYEGERIA_ISSUES.md): seven AssetMaker +action/process queries defaulted `activity_status_list` to ["IN_PROGRESS"], +which silently dropped JournalEntries (no activity status) and every +finished action. The default is now None: no status filter is sent. + +No live server needed: a mocked `_async_make_request` captures the body. +""" +import json +from unittest.mock import MagicMock, patch + +import pytest + +from pyegeria.omvs.asset_maker import AssetMaker + +CALLS = [ + ("find_processes", ("*",)), + ("get_processes_by_category", ("cat",)), + ("get_action_targets", ("g",)), + ("get_actions_for_action_target", ("g",)), + ("get_assigned_actions", ("g",)), + ("get_actions_for_sponsor", ("g",)), + ("get_actions_for_requester", ("g",)), +] + + +def _client(): + with patch("pyegeria.core._base_server_client.BaseServerClient.check_connection", return_value=""): + return AssetMaker(view_server="vs", platform_url="https://localhost:9443", user_id="u", user_pwd="p") + + +def _capture(client): + cap = {} + + async def fake(method, url, body=None, **kwargs): + cap["url"] = url + cap["body"] = json.loads(body) if isinstance(body, str) else (body or {}) + resp = MagicMock() + resp.json = MagicMock(return_value={"elements": []}) + return resp + + client._async_make_request = fake + return cap + + +@pytest.mark.parametrize("name,args", CALLS) +def test_default_sends_no_activity_status_filter(name, args): + client = _client() + cap = _capture(client) + getattr(client, name)(*args) + assert not cap["body"].get("activityStatusList") + + +@pytest.mark.parametrize("name,args", CALLS) +def test_explicit_filter_is_still_sent(name, args): + client = _client() + cap = _capture(client) + getattr(client, name)(*args, activity_status_list=["IN_PROGRESS"]) + assert cap["body"]["activityStatusList"] == ["IN_PROGRESS"] From 4f0a4003f7b2a0141355870b616eb1523caaaa38 Mon Sep 17 00:00:00 2001 From: Dan Wolfson Date: Tue, 13 Oct 2026 19:32:14 -0500 Subject: [PATCH 3/6] docs(issues): log ISSUE-149/150 (analytic manifest fields, Analytic Function Dr.Egeria family); 137/141 shipped in 6.2.2 Handed off by the Resource Explorer PR/CI session on the owner's instruction, from trellis' analytic walking-skeleton brief. A1-A5 of the handoff were already logged as ISSUE-137..141 (137 and 141 are fixed and released in 6.2.2). Signed-off-by: Dan Wolfson --- PYEGERIA_ISSUES.md | 57 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 55 insertions(+), 2 deletions(-) diff --git a/PYEGERIA_ISSUES.md b/PYEGERIA_ISSUES.md index e9bfa074..a3bc586b 100644 --- a/PYEGERIA_ISSUES.md +++ b/PYEGERIA_ISSUES.md @@ -151,6 +151,8 @@ content was changed. The numbered section list above describes the **At a glance** — 7 open pyegeria items, 7 awaiting re-test, 7 open Egeria Server issues. **Open pyegeria items** +- ISSUE-150: No Dr.Egeria commands for an Analytic Function's Egeria declaration (create/update/retire, join a family Collection, view); the element type is an open question for the Egeria leads +- ISSUE-149: `AnalyticFunctionSpec` lacks the manifest fields trellis-analytics needs (`kind`, `source`, `version`, `envelope`, `annotation_type`, `resource_types`), so trellis subclasses carry them - ISSUE-146: Deleting a journal entry fails with OMAG-REPOSITORY-HANDLER-400-008, and pyegeria's `remove_note` reaches the delete only through the generic Asset Maker service - ISSUE-140: The executor charts any dict with two or more top-level numbers, regardless of the result's state - ISSUE-139: The executor renders no result envelope, and the Vega bar chart has no subtitle, so a not-established result has nowhere to say so on a chart @@ -188,6 +190,57 @@ into the entry now, so it isn't rediscovered from scratch later. --- +### ISSUE-150: No Dr.Egeria commands for an Analytic Function's Egeria declaration (create/update/retire, join a family Collection, view); the element type is an open question for the Egeria leads + +**Layer:** Dr.Egeria (new command family) · **Status:** open, design blocked on the element type · **Found:** 2026-10-13, handed off by the Resource Explorer PR/CI session on the owner's instruction ("kick off the other items ... hand off egeria-python items to the agent there"). Source: trellis `docs/extensibility-walking-skeleton-brief.md` §3a (the table row "create, update, retire the declaration in Egeria; join a family Collection") and §2c. + +**What's wanted:** a Dr.Egeria family for the Egeria side of the Analytic Library. The local registry answers "what can run here"; Egeria answers "what exists and who declared it". +- `Create Analytic Function`, `Update Analytic Function`; +- `Retire Analytic Function`: retirement is a **status**, never a delete; +- `Link Analytic Function to Family`: a family is an Egeria `Collection`, the same word as `FormatSet.family`; +- `View Analytic Functions [family]`. +`trellis-analytics declare ` generates the Dr.Egeria document from the manifest, so the attribute names must line up with ISSUE-149's fields. The brief's skeleton scope is `Create Analytic Function` only; the other four follow once a second function exists. + +**Open design question (do not hard-wire before the owner or Mandy answer):** brief §2c proposes a `GovernanceActionType`-shaped declaration, "the same family the survey definitions use", so a Survey Definition can reference a user step the way it references RE's built-in steps. Brief §8 asks the Egeria leads whether `GovernanceActionType` is right for a step Egeria does not run. Candidates: +1. **`GovernanceActionType`.** It fits Survey Definition references, and `GovernanceProcessor` already handles this family. But it implies an engine-host executor the step doesn't have. +2. **A `DeployedSoftwareComponent`/`SoftwareCapability`-style Asset**, created through `AssetMaker._async_create_asset` (the pattern `Create Report` uses). It's neutral about who runs the code, but Survey Definitions can't reference it as a step today. +3. **A plain `Referenceable` subtype with `additionalProperties`.** It's the smallest, but it leaves `kind`/`source`/`version` untyped. +Whichever is chosen, retirement maps to a status update (the element header status, or `deploymentStatus` for an Asset), never a delete. + +**Work once the type is decided:** +- compact-spec family via the Spec Editor API; +- processor and dispatcher registration (`register_governance_processors()` is family-name-gated, so a new family name must be added there if option 1 is chosen); +- `refresh_specs`; +- a regression doc in `tests/dr-egeria-command-tests/`; +- a live round on a throwaway function, after a peer round. + +--- + +### ISSUE-149: `AnalyticFunctionSpec` lacks the manifest fields trellis-analytics needs (`kind`, `source`, `version`, `envelope`, `annotation_type`, `resource_types`), so trellis subclasses carry them + +**Layer:** pyegeria (`pyegeria/view/analytic_registry.py`) · **Status:** open · **Found:** 2026-10-13, handed off by the Resource Explorer PR/CI session on the owner's instruction. Source: trellis brief §2a and `packages/trellis-analytics/src/trellis_analytics/manifest.py`. RE runs pyegeria 6.2.2. + +**What:** trellis-analytics' `RoutineManifest`/`StepManifest` subclass `AnalyticFunctionSpec` only to add fields the base should carry: +- `kind`; +- `source`; +- `version`; +- `envelope: bool` (the result carries a state envelope; see ISSUE-139/140); +- `annotation_type` (a step's result type, empty for a routine); +- `resource_types: list[str]`. + +The Portal's "Analytic Functions" tab groups by `family`, then `kind`, then `source`. + +**Proposed change:** add all six as optional fields with defaults (`kind="routine"`, `source=""`, `version=""`, `envelope=False`, `annotation_type=""`, `resource_types=[]`), so every existing registry entry and spec still validates unchanged. Once a pyegeria release carries them, trellis-analytics drops its own copies. + +**Points to settle before building:** +- The handoff lists `kind` as `routine | step | spec`, but trellis's `Kind` is `Literal["routine", "step"]`. Decide whether `spec` is a third kind or a different axis (a report spec is the presentation flavour, brief §2d). +- trellis's manifest also carries `family` and `tags`, which the handoff doesn't list. `FormatSet` already has `family`; decide whether `AnalyticFunctionSpec` should get them too, rather than leaving trellis to carry them. +- `source` values in trellis are `ods | egeria | resource`. Decide between a `Literal` (strict) and `str` (open, so a user step can name a new source). + +**Related:** ISSUE-138 (non-client param binding), ISSUE-139/140 (envelope rendering), ISSUE-150 (the Egeria declaration, which should take its attribute names from these fields). + +--- + ### ISSUE-146: Deleting a journal entry fails with OMAG-REPOSITORY-HANDLER-400-008, and pyegeria's `remove_note` reaches the delete only through the generic Asset Maker service @@ -1688,7 +1741,7 @@ sends `confidence` (`collection_manager.py`, ### ISSUE-141: `ActionParameter.function` is a required string, so analytic-only specs must pass `""`, and the Advisor's validator then warns "No Action Function" -**Layer:** pyegeria (report spec models) · **Status:** fixed 2026-10-12 on branch `docs/issue-136` (PR pending), not yet released · **Found:** 2026-10-12, reported by the Resource Explorer PR/CI session from trellis-analytics (trellis PR #622, `trellis_analytics/portal.py`), which works around it today. +**Layer:** pyegeria (report spec models) · **Status:** fixed 2026-10-12 in #446, released in 6.2.2 · **Found:** 2026-10-12, reported by the Resource Explorer PR/CI session from trellis-analytics (trellis PR #622, `trellis_analytics/portal.py`), which works around it today. **Fixed 2026-10-12:** `function` is now `Optional[str] = None`, and a model validator rejects an action with neither `function` nor `analytic_function`. An @@ -1715,7 +1768,7 @@ and teach the validator the same rule. ### ISSUE-137: `exec_report_spec` always builds an `EgeriaTech` client and mints a token, even for an analytic routine that needs no Egeria -**Layer:** pyegeria (format_set_executor) · **Status:** fixed 2026-10-12 on branch `docs/issue-136` (PR pending), not yet released · **Found:** 2026-10-12, reported by the Resource Explorer PR/CI session from trellis-analytics (trellis PR #622, `trellis_analytics/portal.py`), which works around it today. +**Layer:** pyegeria (format_set_executor) · **Status:** fixed 2026-10-12 in #446, released in 6.2.2 · **Found:** 2026-10-12, reported by the Resource Explorer PR/CI session from trellis-analytics (trellis PR #622, `trellis_analytics/portal.py`), which works around it today. **Fixed 2026-10-12:** `_run_analytic_function` counts the routine's leading client parameters (`_count_client_params`) and builds and authenticates an From adea14541712148c9e6f395e4ac7a3a272aba1bf Mon Sep 17 00:00:00 2001 From: Dan Wolfson Date: Tue, 13 Oct 2026 19:33:22 -0500 Subject: [PATCH 4/6] docs(issues): record ISSUE-149 design answers from the RE handoff Signed-off-by: Dan Wolfson --- PYEGERIA_ISSUES.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/PYEGERIA_ISSUES.md b/PYEGERIA_ISSUES.md index a3bc586b..166a178a 100644 --- a/PYEGERIA_ISSUES.md +++ b/PYEGERIA_ISSUES.md @@ -239,6 +239,13 @@ The Portal's "Analytic Functions" tab groups by `family`, then `kind`, then `sou **Related:** ISSUE-138 (non-client param binding), ISSUE-139/140 (envelope rendering), ISSUE-150 (the Egeria declaration, which should take its attribute names from these fields). +**Answers (RE PR/CI session, 2026-10-13, citing the owner's 2026-10-07 organisation ruling; to be confirmed by the owner before building):** +- `kind`: `routine | step` only. "spec" was a slip: a spec is a `FormatSet`, not an `AnalyticFunctionSpec`. This matches trellis-analytics' `Kind` (`manifest.py:14`). +- `family` and `tags`: add both, optional. `family` has the same word and meaning as `FormatSet.family`; in Egeria a family is a `Collection`. +- `source`: an open `str`, not a `Literal`. Document the known values (`ods`, `egeria`). The owner's rule for value lists is "suggestive everywhere": an unknown value warns, never rejects. +- The Advisor side of ISSUE-141 is already done in trellis (`packages/egeria-advisor/tests/unit/test_report_spec_parser.py:263-267`). +- Once a pyegeria release carries these fields, trellis-analytics drops its own copies. Tell the RE PR/CI session the version. + --- From c883f0631e2cc9d74da4e02868666073ea7305ca Mon Sep 17 00:00:00 2001 From: Dan Wolfson Date: Tue, 13 Oct 2026 19:58:24 -0500 Subject: [PATCH 5/6] docs(issues): log ISSUE-151 (get_engine_actions calls a View Server path that doesn't exist) Reported by the RE PR/CI session; confirmed from AutomatedCurationResource and a read-only live check. find_engine_actions("*") is the working route. Signed-off-by: Dan Wolfson --- PYEGERIA_ISSUES.md | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/PYEGERIA_ISSUES.md b/PYEGERIA_ISSUES.md index 166a178a..c99ee069 100644 --- a/PYEGERIA_ISSUES.md +++ b/PYEGERIA_ISSUES.md @@ -151,6 +151,7 @@ content was changed. The numbered section list above describes the **At a glance** — 7 open pyegeria items, 7 awaiting re-test, 7 open Egeria Server issues. **Open pyegeria items** +- ISSUE-151: `AutomatedCuration.get_engine_actions()` calls `automated-curation/engine-actions`, which the View Server doesn't have (404, reported as "unable to connect"); `find_engine_actions("*")` is the working list-all - ISSUE-150: No Dr.Egeria commands for an Analytic Function's Egeria declaration (create/update/retire, join a family Collection, view); the element type is an open question for the Egeria leads - ISSUE-149: `AnalyticFunctionSpec` lacks the manifest fields trellis-analytics needs (`kind`, `source`, `version`, `envelope`, `annotation_type`, `resource_types`), so trellis subclasses carry them - ISSUE-146: Deleting a journal entry fails with OMAG-REPOSITORY-HANDLER-400-008, and pyegeria's `remove_note` reaches the delete only through the generic Asset Maker service @@ -190,6 +191,39 @@ into the entry now, so it isn't rediscovered from scratch later. --- +### ISSUE-151: `AutomatedCuration.get_engine_actions()` calls `automated-curation/engine-actions`, which the View Server doesn't have (404, reported as "unable to connect"); `find_engine_actions("*")` is the working list-all + +**Layer:** pyegeria (`pyegeria/omvs/automated_curation.py`) · **Status:** open, logged only (no fix without the owner's word) · **Found:** 2026-10-13 by RE's engine-host design work (the RE PR/CI session confirmed it live on pyegeria 6.2.2). Cause confirmed from Egeria source, and re-checked live read-only, by this session. + +**What:** `_async_get_engine_actions` (~line 2628) posts, through `_async_get_name_request`, to +`{ref_curation_command_base}/engine-actions`. That path doesn't exist. On qs-view-server it answers HTTP 404, which pyegeria surfaces as `PyegeriaClientException` `CLIENT_ERROR_400` with "unable to connect to the Egeria platform". That message is misleading: the platform is reachable, and only the path is wrong. `print_engine_actions()` (~line 5351) calls it, so that fails too. + +**Diagnosis: (b), the View Server has no such endpoint.** It isn't a wrong verb or a wrong path for an endpoint that exists. `AutomatedCurationResource.java` (Egeria `af400039c2`, `view-server-generic-services/automated-curation/automated-curation-spring/...`) maps these engine-action routes: +- `GET /engine-actions/active` (line 435); +- `GET /governance-engines/{guid}/engine-actions/active-claimed` (line 529); +- `POST /engine-actions/{guid}/cancel`, `/claim`, `/status/update`, `/completion-status` (lines 406, 498, 469, 591); +- `POST /engine-actions/action-targets/update` (562); +- `POST /governance-engines/{name}/engine-actions/initiate` (321). + +There is no list-all, and no plain `/engine-actions`. `Egeria-api-automated-curation.http` has no such call either. + +**Working routes today (checked live, read-only, 2026-10-13):** +- **Every engine action:** `find_engine_actions("*")`. It posts to `automated-curation/assets/by-search-string` with `metadata_element_type="EngineAction"`, because in 6.2 EngineAction is an Asset (EngineAction → Action → Process → Asset). It returned a full page of 50, all `COMPLETED`. +- **Only the active ones:** `get_active_engine_actions()`, which returned 1. +- AssetMaker's `find_processes(metadata_element_type="EngineAction")` also works, and since ISSUE-148 it applies no status filter by default. + +**Candidate fixes (needs the owner's choice):** +1. Re-implement `get_engine_actions` as a thin wrapper over `find_engine_actions("*")`, keeping its signature and paging. `print_engine_actions` then works unchanged. (Preferred: callers keep working.) +2. Deprecate it with a clear error naming `find_engine_actions`. + +Either way, add a micro-test that pins the URL. + +**Related, for when Egeria exposes it:** Mandy added a per-engine "approved, unclaimed" engine-action listing on 2026-10-05, but only on the metadata server's `governance-context-service`, not on the View Server, so pyegeria can't reach it through a view service today. RE will ask the Egeria leads to expose it on Automated Curation. Once it's there, add a wrapper next to `get_active_claimed_engine_actions` (same per-engine shape). Until then, approximate it client-side with `find_engine_actions` plus an activity-status filter. + +**Side note (separate, not fixed here):** a 404 reported as "unable to connect" is the same family as the other misleading error labels (compare ISSUE-142). A 404 from a reachable platform should say "endpoint not found". + +--- + ### ISSUE-150: No Dr.Egeria commands for an Analytic Function's Egeria declaration (create/update/retire, join a family Collection, view); the element type is an open question for the Egeria leads **Layer:** Dr.Egeria (new command family) · **Status:** open, design blocked on the element type · **Found:** 2026-10-13, handed off by the Resource Explorer PR/CI session on the owner's instruction ("kick off the other items ... hand off egeria-python items to the agent there"). Source: trellis `docs/extensibility-walking-skeleton-brief.md` §3a (the table row "create, update, retire the declaration in Egeria; join a family Collection") and §2c. From d73b162f307aa4326db17a216cdcc63389058449 Mon Sep 17 00:00:00 2001 From: Dan Wolfson Date: Tue, 13 Oct 2026 20:02:04 -0500 Subject: [PATCH 6/6] fix(automated-curation): remove get_engine_actions; no View Server endpoint (ISSUE-151) get_engine_actions posted to automated-curation/engine-actions, which AutomatedCurationResource does not map, so it always failed with a 404 (reported as "unable to connect"). EngineAction is an Asset in 6.2, so find_engine_actions("*") is the list-all; print_engine_actions now uses it. No callers outside egeria-python (checked egeria-workspaces-fs and trellis). API removal noted for the 6.2.3 release notes. Signed-off-by: Dan Wolfson --- BACKLOG.md | 1 + PYEGERIA_ISSUES.md | 74 +++++++------ docs/parameter_cleanup_plan.md | 2 +- pyegeria/omvs/automated_curation.py | 101 +----------------- .../test_automated_curation.py | 6 +- .../test_issue_151_engine_actions_list_all.py | 45 ++++++++ 6 files changed, 95 insertions(+), 134 deletions(-) create mode 100644 tests/micro-tests/test_issue_151_engine_actions_list_all.py diff --git a/BACKLOG.md b/BACKLOG.md index 0efc7dec..a726f0ac 100644 --- a/BACKLOG.md +++ b/BACKLOG.md @@ -17,6 +17,7 @@ Once the Egeria release with the delete fixes is published and the local quickst Also ISSUE-147, the valid-metadata clears: re-run the ISSUE-147 sequence (setup then clear for a value, a map name and a map value on a made-up property). Expect no 400-011 error after a successful clear, and expect the map value to actually be removed. 3. Update each `PYEGERIA_ISSUES.md` entry with the result, then do the held 6.2.3 release. The owner wants outstanding issues fixed before releasing. **The 6.2.3 release notes must list this behaviour change:** ISSUE-148. `AssetMaker.find_processes`, `get_processes_by_category`, `get_action_targets`, `get_actions_for_action_target`, `get_assigned_actions`, `get_actions_for_sponsor` and `get_actions_for_requester` now default `activity_status_list` to `None` (no filter) instead of `["IN_PROGRESS"]`. A caller that relied on getting only in-progress actions by default now also gets completed, cancelled and status-less actions (e.g. journal entries), so it should pass `["IN_PROGRESS"]` explicitly. + **Also list this API removal:** ISSUE-151. `AutomatedCuration.get_engine_actions()` is removed, because the View Server has no list-all endpoint for it (it always got a 404). Use `find_engine_actions("*")` instead. --- diff --git a/PYEGERIA_ISSUES.md b/PYEGERIA_ISSUES.md index c99ee069..5adf4be4 100644 --- a/PYEGERIA_ISSUES.md +++ b/PYEGERIA_ISSUES.md @@ -151,7 +151,6 @@ content was changed. The numbered section list above describes the **At a glance** — 7 open pyegeria items, 7 awaiting re-test, 7 open Egeria Server issues. **Open pyegeria items** -- ISSUE-151: `AutomatedCuration.get_engine_actions()` calls `automated-curation/engine-actions`, which the View Server doesn't have (404, reported as "unable to connect"); `find_engine_actions("*")` is the working list-all - ISSUE-150: No Dr.Egeria commands for an Analytic Function's Egeria declaration (create/update/retire, join a family Collection, view); the element type is an open question for the Egeria leads - ISSUE-149: `AnalyticFunctionSpec` lacks the manifest fields trellis-analytics needs (`kind`, `source`, `version`, `envelope`, `annotation_type`, `resource_types`), so trellis subclasses carry them - ISSUE-146: Deleting a journal entry fails with OMAG-REPOSITORY-HANDLER-400-008, and pyegeria's `remove_note` reaches the delete only through the generic Asset Maker service @@ -191,38 +190,6 @@ into the entry now, so it isn't rediscovered from scratch later. --- -### ISSUE-151: `AutomatedCuration.get_engine_actions()` calls `automated-curation/engine-actions`, which the View Server doesn't have (404, reported as "unable to connect"); `find_engine_actions("*")` is the working list-all - -**Layer:** pyegeria (`pyegeria/omvs/automated_curation.py`) · **Status:** open, logged only (no fix without the owner's word) · **Found:** 2026-10-13 by RE's engine-host design work (the RE PR/CI session confirmed it live on pyegeria 6.2.2). Cause confirmed from Egeria source, and re-checked live read-only, by this session. - -**What:** `_async_get_engine_actions` (~line 2628) posts, through `_async_get_name_request`, to -`{ref_curation_command_base}/engine-actions`. That path doesn't exist. On qs-view-server it answers HTTP 404, which pyegeria surfaces as `PyegeriaClientException` `CLIENT_ERROR_400` with "unable to connect to the Egeria platform". That message is misleading: the platform is reachable, and only the path is wrong. `print_engine_actions()` (~line 5351) calls it, so that fails too. - -**Diagnosis: (b), the View Server has no such endpoint.** It isn't a wrong verb or a wrong path for an endpoint that exists. `AutomatedCurationResource.java` (Egeria `af400039c2`, `view-server-generic-services/automated-curation/automated-curation-spring/...`) maps these engine-action routes: -- `GET /engine-actions/active` (line 435); -- `GET /governance-engines/{guid}/engine-actions/active-claimed` (line 529); -- `POST /engine-actions/{guid}/cancel`, `/claim`, `/status/update`, `/completion-status` (lines 406, 498, 469, 591); -- `POST /engine-actions/action-targets/update` (562); -- `POST /governance-engines/{name}/engine-actions/initiate` (321). - -There is no list-all, and no plain `/engine-actions`. `Egeria-api-automated-curation.http` has no such call either. - -**Working routes today (checked live, read-only, 2026-10-13):** -- **Every engine action:** `find_engine_actions("*")`. It posts to `automated-curation/assets/by-search-string` with `metadata_element_type="EngineAction"`, because in 6.2 EngineAction is an Asset (EngineAction → Action → Process → Asset). It returned a full page of 50, all `COMPLETED`. -- **Only the active ones:** `get_active_engine_actions()`, which returned 1. -- AssetMaker's `find_processes(metadata_element_type="EngineAction")` also works, and since ISSUE-148 it applies no status filter by default. - -**Candidate fixes (needs the owner's choice):** -1. Re-implement `get_engine_actions` as a thin wrapper over `find_engine_actions("*")`, keeping its signature and paging. `print_engine_actions` then works unchanged. (Preferred: callers keep working.) -2. Deprecate it with a clear error naming `find_engine_actions`. - -Either way, add a micro-test that pins the URL. - -**Related, for when Egeria exposes it:** Mandy added a per-engine "approved, unclaimed" engine-action listing on 2026-10-05, but only on the metadata server's `governance-context-service`, not on the View Server, so pyegeria can't reach it through a view service today. RE will ask the Egeria leads to expose it on Automated Curation. Once it's there, add a wrapper next to `get_active_claimed_engine_actions` (same per-engine shape). Until then, approximate it client-side with `find_engine_actions` plus an activity-status filter. - -**Side note (separate, not fixed here):** a 404 reported as "unable to connect" is the same family as the other misleading error labels (compare ISSUE-142). A 404 from a reachable platform should say "endpoint not found". - ---- ### ISSUE-150: No Dr.Egeria commands for an Analytic Function's Egeria declaration (create/update/retire, join a family Collection, view); the element type is an open question for the Egeria leads @@ -1657,6 +1624,47 @@ Sorted newest-first by `ISSUE-#` (2026-10-12). ISSUE-91 has two entries --- +### ISSUE-151: `AutomatedCuration.get_engine_actions()` calls `automated-curation/engine-actions`, which the View Server doesn't have (404, reported as "unable to connect"); `find_engine_actions("*")` is the working list-all + +**Layer:** pyegeria (`pyegeria/omvs/automated_curation.py`) · **Status:** fixed 2026-10-13 (method removed) · **Found:** 2026-10-13 by RE's engine-host design work (the RE PR/CI session confirmed it live on pyegeria 6.2.2). Cause confirmed from Egeria source, and re-checked live read-only, by this session. + +**What:** `_async_get_engine_actions` (~line 2628) posts, through `_async_get_name_request`, to +`{ref_curation_command_base}/engine-actions`. That path doesn't exist. On qs-view-server it answers HTTP 404, which pyegeria surfaces as `PyegeriaClientException` `CLIENT_ERROR_400` with "unable to connect to the Egeria platform". That message is misleading: the platform is reachable, and only the path is wrong. `print_engine_actions()` (~line 5351) calls it, so that fails too. + +**Diagnosis: (b), the View Server has no such endpoint.** It isn't a wrong verb or a wrong path for an endpoint that exists. `AutomatedCurationResource.java` (Egeria `af400039c2`, `view-server-generic-services/automated-curation/automated-curation-spring/...`) maps these engine-action routes: +- `GET /engine-actions/active` (line 435); +- `GET /governance-engines/{guid}/engine-actions/active-claimed` (line 529); +- `POST /engine-actions/{guid}/cancel`, `/claim`, `/status/update`, `/completion-status` (lines 406, 498, 469, 591); +- `POST /engine-actions/action-targets/update` (562); +- `POST /governance-engines/{name}/engine-actions/initiate` (321). + +There is no list-all, and no plain `/engine-actions`. `Egeria-api-automated-curation.http` has no such call either. + +**Working routes today (checked live, read-only, 2026-10-13):** +- **Every engine action:** `find_engine_actions("*")`. It posts to `automated-curation/assets/by-search-string` with `metadata_element_type="EngineAction"`, because in 6.2 EngineAction is an Asset (EngineAction → Action → Process → Asset). It returned a full page of 50, all `COMPLETED`. +- **Only the active ones:** `get_active_engine_actions()`, which returned 1. +- AssetMaker's `find_processes(metadata_element_type="EngineAction")` also works, and since ISSUE-148 it applies no status filter by default. + +**Candidate fixes (needs the owner's choice):** +1. Re-implement `get_engine_actions` as a thin wrapper over `find_engine_actions("*")`, keeping its signature and paging. `print_engine_actions` then works unchanged. (Preferred: callers keep working.) +2. Deprecate it with a clear error naming `find_engine_actions`. + +Either way, add a micro-test that pins the URL. + +**Related, for when Egeria exposes it:** Mandy added a per-engine "approved, unclaimed" engine-action listing on 2026-10-05, but only on the metadata server's `governance-context-service`, not on the View Server, so pyegeria can't reach it through a view service today. RE will ask the Egeria leads to expose it on Automated Curation. Once it's there, add a wrapper next to `get_active_claimed_engine_actions` (same per-engine shape). Until then, approximate it client-side with `find_engine_actions` plus an activity-status filter. + +**Side note (separate, not fixed here):** a 404 reported as "unable to connect" is the same family as the other misleading error labels (compare ISSUE-142). A 404 from a reachable platform should say "endpoint not found". + +**Fixed 2026-10-13 (owner: "remove it and let people use find_engine_actions"):** +`get_engine_actions` / `_async_get_engine_actions` are removed. Before removing them, callers were searched in +egeria-python, egeria-workspaces-fs and trellis. The only callers were in egeria-python: `print_engine_actions`, +one functional test and a docs checklist line. `print_engine_actions` now calls `find_engine_actions("*")`. +The functional test is now `test_find_all_engine_actions`. Test: +`tests/micro-tests/test_issue_151_engine_actions_list_all.py`. **This is a public API removal, so it must go in +the 6.2.3 release notes** (see BACKLOG.md). + +--- + ### ISSUE-148: AssetMaker action/process queries default `activity_status_list` to `["IN_PROGRESS"]`, which silently drops JournalEntries and any other Action with no activity status **Layer:** pyegeria (`pyegeria/omvs/asset_maker.py`) · **Status:** fixed 2026-10-13 · **Found:** 2026-10-13 by the egeria-workspaces-fs session (Resource Locator) on pyegeria 6.2.0 in quickstart-pyegeria-web. diff --git a/docs/parameter_cleanup_plan.md b/docs/parameter_cleanup_plan.md index b2fd9d2c..b5f74612 100644 --- a/docs/parameter_cleanup_plan.md +++ b/docs/parameter_cleanup_plan.md @@ -340,7 +340,7 @@ async def _async_get_xxx_by_guid( - **Planned**: TODO - [ ] `get_create_csv_data_file_element_from_template(self, file_name, file_type, file_path_name, version_identifier, file_encoding='UTF-8', file_extension='csv', file_system_name=None, description=None)` - **Planned**: TODO -- [ ] `get_engine_actions(self, start_from=0, page_size=0, output_format='JSON', report_spec='EngineAction', body=None)` +- [x] ~~`get_engine_actions(...)`~~ removed (ISSUE-151): no View Server endpoint; use `find_engine_actions("*")` - **Planned**: TODO - [x] `get_engine_actions_by_name(self, name, start_from=0, page_size=0, output_format='JSON', report_spec='EngineAction', body=None)` - **Planned**: Standard Get By Name Pattern diff --git a/pyegeria/omvs/automated_curation.py b/pyegeria/omvs/automated_curation.py index c8f2421c..2ecea735 100644 --- a/pyegeria/omvs/automated_curation.py +++ b/pyegeria/omvs/automated_curation.py @@ -2625,103 +2625,6 @@ def get_active_claimed_engine_actions( self._async_get_active_claimed_engine_actions(governance_engine_guid, start_from, page_size) ) - async def _async_get_engine_actions( - self, - start_from: int = 0, - page_size: int = 0, - output_format: str = "JSON", - report_spec: str | dict = "EngineAction", - body: Optional[dict | FilterRequestBody] = None, - **kwargs, - ) -> list | str: - """Retrieve the list of engine action metadata elements. - - Async version. - - Parameters - ---------- - start_from : int, default 0 - The index from which to start fetching. - page_size : int, default 0 - The maximum number to fetch in a single request. - output_format : str, default "JSON" - The desired output format (e.g., "JSON", "DICT"). - report_spec : str | dict, default "EngineAction" - The report specification to use for formatting. - body : dict | FilterRequestBody, optional - The request body. - **kwargs : Any - Additional keyword arguments to pass to the request. - - Returns - ------- - list | str - A list of dictionaries representing the retrieved engine actions. - - Raises - ------ - PyegeriaException - If there is an error in communication or processing. - - Notes - ----- - For more information see: https://egeria-project.org/concepts/engine-action - """ - - url = f"{self.ref_curation_command_base}/engine-actions" - response = await self._async_get_name_request(url, _type=self.ENGINE_ACTION_LABEL, - _gen_output=self._generate_engine_action_output, - filter_string=None, start_from=start_from, page_size=page_size, - output_format=output_format, report_spec=report_spec, body=body, **kwargs) - return response - - def get_engine_actions( - self, - start_from: int = 0, - page_size: int = 0, - output_format: str = "JSON", - report_spec: str | dict = "EngineAction", - body: Optional[dict | FilterRequestBody] = None, - **kwargs, - ) -> list | str: - """Retrieve the list of engine action metadata elements. - - Parameters - ---------- - start_from : int, optional - The index to start retrieving engine actions from. If not provided, the default value will be used. - page_size : int, optional - The maximum number of engine actions to retrieve in a single request. If not provided, the default global - maximum paging size will be used. - output_format: str, default = "JSON" - - one of "DICT", "MERMAID" or "JSON" - report_spec: dict , optional, default = None - The desired output columns/fields to include. - body: dict, optional, default = None - Provides, a full request body. - **kwargs : Any - Additional keyword arguments to pass to the request. - - Returns - ------- - list of dict | str - A list of dictionaries representing the retrieved engine actions. - Raises: - ------ - PyegeriaException - Notes - ----- - For more information see: https://egeria-project.org/concepts/engine-action - - """ - loop = asyncio.get_event_loop() - response = loop.run_until_complete( - self._async_get_engine_actions( - start_from, page_size, output_format, report_spec, body, **kwargs - ) - ) - return response - async def _async_get_active_engine_actions( self, start_from: int = 0, @@ -5350,7 +5253,9 @@ def print_engine_action_summary(self, governance_action: dict): def print_engine_actions(self): """Print all the engine actions.""" - governance_actions = self.get_engine_actions() + # The View Server has no list-all engine-actions endpoint (ISSUE-151); EngineAction + # is an Asset in 6.2, so the asset search is the list-all. + governance_actions = self.find_engine_actions("*") if governance_actions is not None and isinstance(governance_actions, list): for x in range(len(governance_actions)): self.print_engine_action_summary(governance_actions[x]) diff --git a/tests/functional-tests/test_automated_curation.py b/tests/functional-tests/test_automated_curation.py index 78ea1291..53f55602 100644 --- a/tests/functional-tests/test_automated_curation.py +++ b/tests/functional-tests/test_automated_curation.py @@ -397,7 +397,9 @@ def test_create_uc_server_element_from_template(self): finally: a_client.close_session() - def test_get_engine_actions(self): + def test_find_all_engine_actions(self): + # get_engine_actions was removed (ISSUE-151): the View Server has no list-all + # endpoint, so find_engine_actions("*") is the list-all. try: a_client = AutomatedCuration( self.good_view_server_2, @@ -409,7 +411,7 @@ def test_get_engine_actions(self): start_time = time.perf_counter() - response = a_client.get_engine_actions(request_id="test-id") + response = a_client.find_engine_actions("*") duration = time.perf_counter() - start_time print(f"\n\tDuration was {duration} seconds") print(f"The type of response is: {type(response)}") diff --git a/tests/micro-tests/test_issue_151_engine_actions_list_all.py b/tests/micro-tests/test_issue_151_engine_actions_list_all.py new file mode 100644 index 00000000..0af7dd34 --- /dev/null +++ b/tests/micro-tests/test_issue_151_engine_actions_list_all.py @@ -0,0 +1,45 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright Contributors to the ODPi Egeria project. +""" +Regression test for ISSUE-151 (PYEGERIA_ISSUES.md): `get_engine_actions` posted +to `automated-curation/engine-actions`, which the View Server does not have +(404). It was removed; `find_engine_actions("*")` is the list-all, and +`print_engine_actions` now uses it. + +No live server needed: a mocked `_async_make_request` captures the URL. +""" +import json +from unittest.mock import MagicMock, patch + +from pyegeria.omvs.automated_curation import AutomatedCuration + + +def _client(): + with patch("pyegeria.core._base_server_client.BaseServerClient.check_connection", return_value=""): + return AutomatedCuration(view_server="vs", platform_url="https://localhost:9443", + user_id="u", user_pwd="p") + + +def test_get_engine_actions_is_removed(): + client = _client() + assert not hasattr(client, "get_engine_actions") + assert not hasattr(client, "_async_get_engine_actions") + + +def test_print_engine_actions_uses_asset_search(): + client = _client() + cap = {} + + async def fake(method, url, body=None, **kwargs): + cap["url"] = url + cap["body"] = json.loads(body) if isinstance(body, str) else (body or {}) + resp = MagicMock() + resp.json = MagicMock(return_value={"elements": []}) + return resp + + client._async_make_request = fake + client.print_engine_actions() + + assert cap["url"].endswith("/automated-curation/assets/by-search-string") + assert not cap["url"].endswith("/engine-actions") + assert cap["body"].get("metadataElementTypeName") == "EngineAction"