You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit f2f9dcb
Browse filesBrowse the repository at this point in the historyBrowse files
docs(issues): log ISSUE-128..134, verify 127/129/131 against Egeria source (#438)
* docs(issues): log ISSUE-128..134, verify 127/129/131 against Egeria source
- ISSUE-128, 130: Egeria server bugs (Retention subtype typo; YAML secrets
store caches users forever), logged by the Resource Explorer session.
- ISSUE-129: get_related_metadata_elements and two linked-by-* siblings drop
paging/lineage arguments. Contract checked against MetadataExpertResource.java:
startingAtEnd is a current query parameter on related-elements only.
- ISSUE-131: 13 (not 27) *_by_name wrappers drop the type filter; the 14
find_* grep hits are correct.
- ISSUE-132: DeleteElementRequestBody sends cascadeDelete, Egeria reads
cascadedDelete and ignores unknown fields. On hold for an Egeria fix.
- ISSUE-133: governance_officer reads subComponents; Egeria 6.2 returns
nestedSolutionComponents.
- ISSUE-134: PYEGERIA_ENABLE_LOGGER_CATCH makes @dynamic_catch return None
on any failure.
- ISSUE-126/127: marked merged in #429; 127 is only partly fixed (ISSUE-132).
Signed-off-by: Dan Wolfson <dan.wolfson@pdr-associates.com>
* docs(issues): ISSUE-131 and ISSUE-133 fixed in #439; correct 133's impact
The governance_officer formatter ISSUE-133 named as the real bug has no callers, so no live output was affected.
Signed-off-by: Dan Wolfson <dan.wolfson@pdr-associates.com>
---------
Signed-off-by: Dan Wolfson <dan.wolfson@pdr-associates.com>
Copy file name to clipboardExpand all lines: PYEGERIA_ISSUES.md
+182-8Lines changed: 182 additions & 8 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -143,6 +143,180 @@ enough to track there too).
143
143
144
144
---
145
145
146
+
### ISSUE-134: With `PYEGERIA_ENABLE_LOGGER_CATCH` on, `@dynamic_catch` turns every failure into a `None` return, indistinguishable from "nothing found"
147
+
148
+
**Layer:** pyegeria · **Status:** open, not fixed · **Found:** 2026-10-10, reported by the Resource Explorer
149
+
session; confirmed from code.
150
+
151
+
**What:** `dynamic_catch` (`pyegeria/core/utils.py` ~439) returns `logger.catch(func)` when
152
+
`app_settings.Debug.enable_logger_catch` is true (`PYEGERIA_ENABLE_LOGGER_CATCH`, `config.py` ~315). loguru's
153
+
`catch` defaults to `reraise=False`, so any exception -- 401, 500, timeout, validation error -- is logged and the
154
+
method returns `None`. Checked with loguru 0.7.3: both a sync and an `async def` function return `None`. It applies
155
+
to all ~1,657 `@dynamic_catch` methods in `pyegeria/omvs/`. The choice is also made once, at import time, so
156
+
changing the setting afterwards has no effect.
157
+
158
+
**Effect:** a caller cannot tell a failed read from an empty one; a `None` can render as "no results". Same family as
159
+
ISSUE-123 (a failed measurement indistinguishable from a real zero). Resource Explorer now treats `None` from a
160
+
wrapped method as "unreadable", never as "no result".
161
+
162
+
**Fix (not made):** pass `reraise=True` to `logger.catch` (keeps the logging, restores the exception), or document
163
+
that the setting is debug-only and must not be used by applications that act on results.
164
+
165
+
---
166
+
167
+
### ISSUE-133: Egeria 6.2 returns a solution component's children as `nestedSolutionComponents`; one pyegeria formatter still reads only `subComponents`
168
+
169
+
**Layer:** pyegeria · **Status:** fixed in #439 (2026-10-10), pending merge · **Found:** 2026-10-10, reported by the Resource Explorer session
170
+
(`SolutionArchitect.get_solution_component_by_guid` JSON on 6.2); confirmed from Egeria source.
171
+
172
+
**What:** Egeria's REST element (`AttributedMetadataElement.java` ~387) carries child components as
173
+
`nestedSolutionComponents` (the `SolutionComposition` relationship, 0730), each a `RelatedMetadataElementSummary`
174
+
(`relatedElement.elementHeader.guid`). It has no `subComponents` field; `subComponents` appears in Egeria only in
175
+
Java archive builders, not in any REST response. A caller reading `subComponents` sees no children.
`subComponents`, so its sub-components column would always be empty. It turned out to have no callers
180
+
(`SolutionArchitect` has its own method of the same name), so no live output was affected.
181
+
- `solution_architect.py` ~609 and ~5181, and `md_processing/v2/solution_architect.py` ~384, already read
182
+
`nestedSolutionComponents`. Each also has a leftover `subComponents` fallback (~675, ~5187, ~388) that never
183
+
matches. These do no harm, but they use the old flat shape (`elementHeader` directly, not `relatedElement`), so they
184
+
would mis-parse if the field ever came back.
185
+
186
+
**Fixed in #439:** `governance_officer.py` reads `nestedSolutionComponents` (through `relatedElement`), and the
187
+
three dead `subComponents` fallbacks are removed. Micro-tests in `tests/micro-tests/test_issue_131_133.py`.
188
+
189
+
---
190
+
191
+
### ISSUE-132: `DeleteElementRequestBody` serializes the cascade flag as `cascadeDelete`; Egeria's field is `cascadedDelete` and unknown fields are ignored, so no pyegeria cascade delete has ever cascaded
192
+
193
+
**Layer:** pyegeria · **Status:** open, on hold: an Egeria fix for cascade delete is coming (owner, 2026-10-10). Wait
194
+
for it, live-test cascade delete against it, then decide the pyegeria change; the fix below may change once the
195
+
Egeria side lands. Confirmed from Egeria source, not yet live-tested · **Found:**
196
+
2026-10-10, while checking ISSUE-129's server contract against Egeria source instead of the `.http` files.
197
+
198
+
**What:** `pyegeria/models/models.py` `DeleteElementRequestBody.cascade_delete` accepts both spellings on input but
199
+
serializes as `serialization_alias="cascadeDelete"`. The comment there records that the `.http` files were split
200
+
about 50/50 and that the choice was unverified (ISSUE-62). Egeria source settles it (`egeria-v6/egeria` at
(`open-metadata-framework/.../search/DeleteOptions.java`), whose field is `cascadedDelete` with
203
+
`getCascadedDelete()`/`setCascadedDelete()`. It is unchanged since 2025-08-04. The class is
204
+
`@JsonAutoDetect(getterVisibility=PUBLIC_ONLY, fieldVisibility=NONE)` and `@JsonIgnoreProperties(ignoreUnknown=true)`,
205
+
with no `@JsonProperty`/`@JsonAlias`, so the JSON name is `cascadedDelete` and `cascadeDelete` is silently ignored.
206
+
207
+
**Effect:** every pyegeria delete that uses `DeleteElementRequestBody` with cascade on (the ISSUE-62 fix,
208
+
`validate_delete_element_request`, ISSUE-127's fix in #429, `MetadataExpert.delete_metadata_element(cascade_delete=True)`)
209
+
sends a flag Egeria discards, so it deletes without cascading. A caller-supplied dict using the correct
210
+
`cascadedDelete` key is also re-serialized as `cascadeDelete`, so even that does not work. The models module's own
211
+
`DeleteRequestBody.cascaded_delete` already uses the right name.
212
+
213
+
**Fix (not made):** change the serialization alias to `cascadedDelete` (keep both spellings accepted on input), and
214
+
fix the 19 `"cascadeDelete"` references in `_server_client.py`, `product_manager.py`, `actor_manager.py`,
215
+
`valid_metadata.py`, `metadata_expert.py` and `reference_data.py` (several are docstring samples). Then live-test one
216
+
cascade delete, and re-test ISSUE-127's `DataStructure` refusal. The `.http` files using `cascadedDelete` are correct;
217
+
the ones using `cascadeDelete` are the ones in error (worth reporting to Egeria).
218
+
219
+
**Lesson:** where the `.http` files disagree with each other, read the Java DTO (getter/setter names plus Jackson
220
+
annotations); do not choose by majority or by what the code already sends.
221
+
222
+
---
223
+
224
+
### ISSUE-131: 13 `*_by_name` wrappers pass `metadata_element_type=`, but `_async_get_name_request` reads `metadata_element_type_name`, so the type filter is silently dropped
225
+
226
+
**Layer:** pyegeria · **Status:** fixed in #439 (2026-10-10), pending merge · **Found:** 2026-10-10, while building Resource Explorer's actor-graph lookups (`get_user_identities_by_name`, `get_actor_profiles_by_name`).
227
+
228
+
**What:** wrappers such as `ActorManager._async_get_user_identities_by_name` (`pyegeria/omvs/actor_manager.py` ~4195) build `params = {"metadata_element_type": metadata_element_type_name, ...}` and call `self._async_get_name_request(url, **params)`. The base method (`pyegeria/core/_server_client.py` ~6581) takes `metadata_element_type_name` and writes it to `"metadataElementTypeName"`, so the wrapper's key falls into `**kwargs` and never reaches the request body. The by-name searches run unfiltered by type.
229
+
230
+
**Scope (checked 2026-10-10):** `grep -rn '"metadata_element_type": metadata_element_type_name' pyegeria` matches 27 lines, but only 13 are broken. The other 14 are `find_*` wrappers that call `_async_find_request`, whose parameter really is `metadata_element_type` (`_server_client.py` ~6468), so they are correct; do not change them. The 13 broken ones are all the `*_by_name` wrappers that call `_async_get_name_request`:
**Root cause:** the two base helpers spell the same argument differently (`_async_find_request(metadata_element_type=...)` vs `_async_get_name_request(metadata_element_type_name=...)`), so a wrapper copied from a `find_*` sibling silently loses the filter.
240
+
241
+
**Effect:** callers relying on the type filter get elements of other types. Resource Explorer works round it by passing a full `FilterRequestBody` with `metadataElementTypeName`.
242
+
243
+
**Fixed in #439:** `_async_get_name_request` accepts both spellings (`metadata_element_type_name` wins if both are given), and the 13 wrappers now use `metadata_element_type_name`. The 14 `find_*` wrappers are unchanged. Micro-tests in `tests/micro-tests/test_issue_131_133.py` capture the request body for each wrapper. Same family as ISSUE-62, ISSUE-127 and ISSUE-129: an argument accepted and silently dropped.
244
+
245
+
---
246
+
247
+
### ISSUE-130: The YAML secrets store's user directory caches a user forever, so editing an existing user needs a platform restart
248
+
249
+
**Layer:** Egeria server (`YAMLSecretsStoreConnector`) · **Status:** open, reported to the Egeria lead · **Found:** 2026-10-09, while adding Resource Explorer's own account (`resourceexplorernpa`).
250
+
251
+
**What:** `getUser(userId)` returns the entry from `userAccountMap` if it is already there. `refreshSecrets()` re-reads the YAML file every `refreshTimeInterval` minutes, but `userAccountMap` (and `securityAccessControlMap`) are created only on the first load (when `secretsStoreFile == null`) and are never cleared afterwards. Re-reading the file only helps users the cache has never seen; the comment says "this may be a new user".
252
+
253
+
**Seen:** the account was first added without its `secrets` block, and the first token request cached it. After the password was added (and matched the servers file), `/api/token` still answered 401 for more than 10 minutes. It worked straight after a platform restart.
254
+
255
+
**Effect:** any change to an existing user (password, status, named-list membership) needs a platform restart.
256
+
257
+
**Fix (Egeria):** clear or rebuild `userAccountMap` and `securityAccessControlMap` in `refreshSecrets()`.
258
+
259
+
---
260
+
261
+
### ISSUE-129: `MetadataExpert.get_related_metadata_elements` (and two sibling relationship queries) accept paging, direction and lineage arguments but never send them
262
+
263
+
**Layer:** pyegeria · **Status:** open, not fixed · **Found:** 2026-10-09, in a code review of Resource Explorer's
`GetOptions` -> `BasicOptions` (`forLineage`, `forDuplicateProcessing`, `effectiveTime`), so the other four
289
+
arguments belong in the body.
290
+
291
+
**Fix (not made):** in the two `related-elements` methods, add `?startingAtEnd={starting_at_end}` to the URL
292
+
(`_async_get_all_related_metadata_elements`, ~2800-2808, already does this and is the pattern to copy), and put
293
+
`startFrom`/`pageSize`/`forLineage`/`forDuplicateProcessing` in the body. In the two `linked-by-*` methods, put
294
+
paging in the body and drop `starting_at_end`. Only add body fields the caller's body does not already set, so
295
+
"body supersedes" (which ISSUE-127 relies on) still holds; the `page_size` default is `max_paging_size`, so
296
+
overwriting would silently change callers who set it in the body.
297
+
298
+
---
299
+
300
+
### ISSUE-128: Retention cannot be set on Egeria 6.2: the server registers the Jackson subtype as `RetentionProperties.class` (typo), and pyegeria only allows `RetentionClassificationProperties`
301
+
302
+
**Status:** open, found 2026-10-09 by Resource Explorer's first Retention publish on Egeria 6.2. **Layer:** Egeria server (a type registration typo). **Decision (owner, 2026-10-09):** wait for the Egeria fix; no pyegeria workaround. Retention publishing stays blocked until then.
303
+
304
+
**What (all proven live on 6.2, with raw HTTP POSTs to `classification-explorer/elements/{guid}/retention` on a throwaway asset):**
305
+
- `"class": "RetentionClassificationProperties"` is refused with `InvalidTypeIdException`. This is what pyegeria documents and whitelists, and it worked on the pre-6.2 server (processors.py comment, 2026-08-03).
306
+
- `"class": "RetentionProperties"` (the `.http` ground truth) is also refused with `InvalidTypeIdException`.
307
+
- `"class": "RetentionProperties.class"` gets **HTTP 200**, and the classification reads back with `retentionBasis` 2 and the notes.
308
+
- The server's known-type list in the error has 96 ids. The only Retention entry is literally `RetentionProperties.class`. That looks like an `@JsonSubTypes.Type(name = "RetentionProperties.class")` typo in Egeria's `ClassificationProperties`.
309
+
- pyegeria's `validate_new_classification_request` whitelist (`prop=["RetentionClassificationProperties"]`) refuses anything else client-side, so no Retention can be set through pyegeria on 6.2.
310
+
311
+
(An earlier version of this entry said 6.2 knows `RetentionProperties`. That was a misread of the error text, corrected the same day.)
312
+
313
+
**Where seen:** Resource Explorer's Curate classifications step on two repository assets. Both were refused, so nothing was written. Confidentiality, Criticality, Confidence and Impact property classes are registered normally.
314
+
315
+
**Candidate fix:**
316
+
1. **Egeria:** correct the subtype name to `RetentionProperties`, matching the `.http` file. Report it to Mandy.
317
+
2. **pyegeria, after Egeria's fix:** change the whitelist and docstring to `RetentionProperties`, the `.http` name. No workaround for the typo, by the owner's decision.
318
+
3. Re-check `md_processing/v2/processors.py` and `v2/curation.py`, which both pin `RetentionClassificationProperties`.
319
+
146
320
### ISSUE-117: Cascade delete that takes the soft-delete (Memento) path fails partway with `OMAG-REPOSITORY-HANDLER-400-010` unless `forLineage=true` — leaves the asset live and an anchored element already soft-deleted
147
321
148
322
**Layer:** Egeria Server · **Status:** open, workaround known, not yet
@@ -1184,8 +1358,7 @@ into the entry now, so it isn't rediscovered from scratch later.
1184
1358
1185
1359
### ISSUE-126: `ProductManager` and `DigitalBusiness` never set `collection_command_root`, so every inherited `CollectionManager` method that uses it raises `AttributeError`
1186
1360
1187
-
**Layer:** pyegeria · **Status:** fixed on branch `fix/issue-126-127-collection-manager-subclasses`
1188
-
(2026-10-05), pending PR/merge · **Found:** 2026-10-05, live cleanup of a throwaway data contract (PR #427's
1361
+
**Layer:** pyegeria · **Status:** fixed, merged to `main` in #429 (`68279835`) · **Found:** 2026-10-05, live cleanup of a throwaway data contract (PR #427's
1189
1362
live check).
1190
1363
1191
1364
**Fix + scope (2026-10-05):** both constructors now call `CollectionManager.__init__`, as `GlossaryManager`
# AttributeError: 'ProductManager' object has no attribute 'collection_command_root'
1205
1378
```
1206
1379
1207
-
**Fix (not made):** call `CollectionManager.__init__` from both constructors, or set the attribute. A test that
1208
-
constructs each `CollectionManager` subclass and asserts the attribute exists would have caught it.
1380
+
**Fixed in #429:** see "Fix + scope" above.
1209
1381
1210
1382
---
1211
1383
1212
1384
### ISSUE-127: `CollectionManager.delete_collection(cascade=True)` silently never sends `cascadeDelete` -- same shape as ISSUE-62
1213
1385
1214
-
**Layer:** pyegeria · **Status:** fixed on branch `fix/issue-126-127-collection-manager-subclasses`
1215
-
(2026-10-05), pending PR/merge · **Found:** 2026-10-05, found by capturing the request body while diagnosing a
1386
+
**Layer:** pyegeria · **Status:** partly fixed in #429 (`68279835`); cascade still blocked by ISSUE-132 · **Found:** 2026-10-05, found by capturing the request body while diagnosing a
1216
1387
failed cleanup.
1217
1388
1218
1389
**Fix + scope (2026-10-05):** a scan of all 42 callers of `_async_delete_element_request` found exactly two
@@ -1230,8 +1401,11 @@ the flag is discarded. Captured: `delete_collection("g", cascade=True)` posts
1230
1401
`{'class': 'DeleteElementRequestBody', 'forLineage': False, 'forDuplicateProcessing': False}` with no
1231
1402
`cascadeDelete`. `MetadataExpert.delete_metadata_element(cascade_delete=True)` does send it.
1232
1403
1233
-
**Fix (not made):** do not pre-fill the body (pass `None` so the helper applies the flag), or put `cascadeDelete` in
1234
-
the pre-filled dict. Worth grepping for other callers that pre-fill a default dict *and* pass a cascade flag.
1404
+
**Fixed in #429, but cascade still does not reach Egeria -- see ISSUE-132.** #429 made the flag reach the request
1405
+
body, but under the name `cascadeDelete`. Egeria's real field is `cascadedDelete`, and it ignores unknown fields, so
1406
+
the flag is still dropped, now on the server side. #429's docstring "correction" from `cascadedDelete` to
1407
+
`cascadeDelete` was also the wrong way round. The `DataStructure` refusal described below is probably this bug
1408
+
rather than an Egeria quirk; re-test once ISSUE-132 is fixed.
1235
1409
1236
1410
**Related, an Egeria quirk found alongside:** even with `cascadeDelete: true`, Egeria refused to delete a
1237
1411
`DataStructure` that still had a member `DataField` (`OMAG-GENERIC-HANDLERS-403-005 ... validateNoMemberDataFields`),
0 commit comments