Skip to content

docs(issues): re-verify all open issues, close 3 as fixed server-side - #275

Merged
dwolfson merged 15 commits into
odpi:mainfrom
dwolfson:fix/pyegeria-http-endpoint-audit
Aug 18, 2026
Merged

docs(issues): re-verify all open issues, close 3 as fixed server-side#275
dwolfson merged 15 commits into
odpi:mainfrom
dwolfson:fix/pyegeria-http-endpoint-audit

Conversation

@dwolfson

Copy link
Copy Markdown
Member

Summary

Follow-up to #274 (merged) — this commit landed on the branch just after that PR merged, so it needs its own PR.

Full re-verification sweep of PYEGERIA_ISSUES.md, prompted by the recent round of pyegeria bug fixes (492b84a) plus a platform redeploy/restart since the last check. Every open issue was re-tested live against the current qs-view-server.

Moved to appendix as resolved (server-side fixes — no pyegeria code change involved; client-side request shapes were already confirmed correct against ground truth before this sweep):

  • ISSUE-53metadataElementSubtypeNames now actually filters (confirmed via both a live find and the native count endpoint matching exactly: 357 = 357).
  • ISSUE-57GovernanceResults relationship no longer rejects the end1/end2 order — link_governance_results now succeeds live.
  • ISSUE-60find_glossary_terms sequencing now produces a genuine continuous sort across pages, not just within one page (verified page 1 → page 2 boundary is seamless A→Z).

Re-confirmed still open, with fresh dated notes:

  • ISSUE-30 (updateNote 404) — unchanged.
  • ISSUE-38 (count_relationships_between_elements off-by-one) — unchanged, identical 58 vs 57.
  • ISSUE-41 (find_glossary_terms combined-filter zero results) — unchanged, though ISSUE-60's fix means the trigger condition may have shifted — flagged for a fresh root-cause look.
  • ISSUE-54 (Referenceable-scoped scan incomplete) — symptom shape changed substantially (494 total elements now vs 19,166 before, zero duplicate GUIDs now vs 39 before) but core incompleteness persists (41% GlossaryTerm coverage). Flagged for a full exhaustive re-scan before considering closed.
  • ISSUE-48, ISSUE-52, ISSUE-55 — not re-tested (deferred pending Egeria API work / infra observation / feature request respectively).

No restructuring of the file's skeleton was needed — the "open issues at top, appendix at bottom" split by who-can-fix-it already existed (established 2026-08-15). This is a content-accuracy pass on top of that skeleton.

Testing

Docs-only change (PYEGERIA_ISSUES.md) — no code changes, no tests to run. All findings above were verified live against qs-view-server.

🤖 Generated with Claude Code

Re-verified every open issue live against the current qs-view-server,
prompted by a round of pyegeria bug fixes (492b84a) and a platform
redeploy/restart since the last check.

Moved to appendix as resolved (server-side fixes, no pyegeria code change --
client-side request shapes were already confirmed correct against ground
truth before this sweep):
- ISSUE-53: metadataElementSubtypeNames now actually filters (confirmed via
  both a live find and the native count endpoint matching exactly).
- ISSUE-57: GovernanceResults relationship no longer rejects end1/end2
  order -- link_governance_results succeeds live now.
- ISSUE-60: find_glossary_terms sequencing_order now produces a genuine
  continuous sort across pages, not just within one page.

Re-confirmed still open, with fresh dated notes:
- ISSUE-30 (updateNote 404) -- unchanged.
- ISSUE-38 (count_relationships_between_elements off-by-one) -- unchanged,
  identical 58 vs 57.
- ISSUE-41 (find_glossary_terms combined-filter zero results) -- unchanged,
  though ISSUE-60's fix means the trigger condition may have shifted --
  flagged for a fresh root-cause look.
- ISSUE-54 (Referenceable-scoped scan incomplete) -- symptom shape changed
  substantially (494 total elements now vs 19,166 before, zero duplicate
  GUIDs now vs 39 before) but core incompleteness persists (41% GlossaryTerm
  coverage). Not re-run as a full exhaustive scan this pass -- flagged for
  one before considering closed.
- ISSUE-48, ISSUE-52, ISSUE-55 -- not re-tested (deferred pending Egeria
  API work / infra observation / feature request respectively; nothing
  about this sweep's fixes plausibly changes their status).

Restructure: the file's "open issues at top, appendix at bottom" skeleton
already existed (established 2026-08-15) -- this pass is a content
accuracy pass on top of that skeleton, moving the 3 newly-confirmed-fixed
entries out of the open section into the appendix where they belong.

Signed-off-by: Dan Wolfson <dan.wolfson@pdr-associates.com>
pyegeria/README.md pointed at "_exceptions_new.py", which doesn't exist --
the real file is pyegeria/core/_exceptions.py (the doc's own example code
already imports from the correct path). Found while auditing docs for
staleness after the recent round of pyegeria fixes.

CLAUDE.md: added a gotcha note under pyegeria/core/ about the extra='ignore'
silent-field-drop hazard ISSUE-62 found in DeleteElementRequestBody -- a
request-body model missing a field validates a caller-supplied dict
successfully and just drops the unknown field before serialization, no
error. Worth flagging generally since other request-body models haven't
all been audited against their real Egeria DTOs the way this one now has.

Signed-off-by: Dan Wolfson <dan.wolfson@pdr-associates.com>
Create Information Supply Chain's Purposes attribute (ISC Base bundle)
validates and processes with SUCCESS but is never persisted to the
element -- confirmed live creating 17 InformationSupplyChain elements
for the Overview dashboard's GovernanceMetric data-flow documentation
(gen_governance_metrics.py), none of which retained their Purposes
value. Worked around by using the standard Description attribute
instead. Root cause not yet found -- flagged as either a processor gap
(Purposes never read from attributes) or a type mismatch (plural name
suggests List<String>, untested).

Signed-off-by: Dan Wolfson <dan.wolfson@pdr-associates.com>
SupplyChainProcessor.apply_changes() built Create/Update Information
Supply Chain's properties body purely from the generic
set_element_prop_body() (Referenceable-level fields only) and never added
InformationSupplyChainProperties-specific fields on top -- so
--validate/--process reported SUCCESS while Purposes/Scope were never
included in the outgoing body at all, unlike sibling domain processors
(e.g. set_collection_manager_body adding Digital-Product-specific fields).

Also found while root-causing: the real Egeria wire property is
"dataProcessingPurposes", not "purposes" (confirmed against
Egeria-api-solution-architect.http's createInformationSupplyChain/
updateInformationSupplyChain worked examples) -- the compact spec's
"Purposes" attribute has no property_name override pointing at this.

Fix: explicitly set prop_body["dataProcessingPurposes"]/prop_body["scope"]
on both Create and Update paths. Verified live: created a real ISC with
both fields set, fetched it back, both persisted correctly. 3 new unit
tests (test_supply_chain_processor.py) cover Create/Update/unset-is-None
via a fake client. Renumbered from a same-day ISSUE-62 collision (kept the
number already burned into DeleteElementRequestBody's code comments,
renumbered this newer duplicate to ISSUE-63 per this file's established
collision convention).

Flagged, not resolved: Integration Style/Estimated Volumetrics (same ISC
Base bundle) have zero ground-truth backing anywhere in
Egeria-api-solution-architect.http -- integrationStyle only exists in this
codebase as a SolutionLinkingWire *relationship* property, suggesting
these two may be misattributed to the wrong bundle rather than sharing
this bug's "processor never reads it" mechanism. Not confirmed against the
real Java class; left as a follow-up.

Also in this commit -- a related but separate fix found while
investigating ISSUE-54 (which had been misdiagnosed hours earlier in the
same day; corrected per Egeria's own paging docs at
https://egeria-project.org/guides/developer/finding-metadata/overview/#paging,
which state a short-but-nonempty page does NOT mean "last page", only a
genuinely empty one does): pyegeria/view/base_report_formats.py's
load_egeria_report_specs() had exactly that len(page) < page_size
anti-pattern in a real fetch-all loop over ReportType collections --
fixed to advance startFrom unconditionally and stop only on an empty page.
Full codebase grep confirms this was the only occurrence.

PYEGERIA_ISSUES.md: corrected ISSUE-54's write-up (real remaining defect
is duplicate GUIDs + ~17% still-missing population when paginated
correctly, not the false short-page signal first suspected), re-confirmed
ISSUE-41 with a traced request body (rules out any pyegeria-side cause
definitively), and closed ISSUE-63 as fixed with full root-cause detail.

pytest tests/micro-tests/ passes in full.

Signed-off-by: Dan Wolfson <dan.wolfson@pdr-associates.com>
…eleteMethod fix

MetadataExpert.delete_related_elements()/_async_delete_related_elements()
and delete_metadata_element()/_async_delete_metadata_element() were left
behind when the deleteMethod-silently-dropped bug (PyegeriaModel's
extra='ignore' swallowing any field a target model doesn't declare) was
fixed for DeleteRelationshipRequestBody and ~15 other OMVS modules, and for
DeleteElementRequestBody (ISSUE-62). Both methods still routed through
OpenMetadataDeleteRequestBody/_async_open_metadata_delete_body_request,
which has no delete_method field at all -- so a caller-supplied
deleteMethod validated successfully and silently vanished, same as the
original bug, unchanged. Since deleteRelationshipInStore rejects its own
default deleteMethod (LookForLineage) with OMAG-COMMON-400-032,
delete_related_elements() (the fallback every caller without a bespoke
"unlink" method reaches for) could never succeed at all on a stock server.

Reported by dwolfson from Resource Explorer's investigation (full report
text preserved in PYEGERIA_ISSUES.md).

Fix: migrated _async_delete_related_elements() to DeleteRelationshipRequestBody
via _async_delete_relationship_request(), and _async_delete_metadata_element()
to DeleteElementRequestBody via _async_delete_element_request() -- exactly
mirroring the pattern already used by _async_archive_metadata_element right
above it in the same file. delete_metadata_element gained a cascade_delete
parameter to match. OpenMetadataDeleteRequestBody itself untouched (it's
correctly fieldless per its own ground truth).

Verified live against qs-view-server: created two throwaway assets + a real
DataFlow relationship. delete_related_elements(guid) with no body still
fails with the same 500 (expected -- Egeria's own default deleteMethod is
still rejected, unchanged); delete_related_elements(guid, {"deleteMethod":
"SOFT_DELETE"}) now succeeds -- the override that was previously impossible
now works end-to-end. delete_metadata_element() on both assets also
succeeded. 6 new unit tests (test_metadata_expert_delete_methods.py).

Also in this commit: renumbered the ISC Purposes/Scope fix from a second
same-day ISSUE-63 collision (this report's number) to ISSUE-64 -- kept the
number here since this report's number was already fixed by its own
author. Updated all cross-references (solution_architect.py comment,
test_supply_chain_processor.py docstring, PYEGERIA_ISSUES.md).

pytest tests/micro-tests/ passes in full.

Signed-off-by: Dan Wolfson <dan.wolfson@pdr-associates.com>
…ndards classification shape gotcha

Cross-posted from a peer session working in egeria-workspaces-fs (Egeria
Explorer's Glossary panel). PrimeWord/ClassWord/Modifier classifications
(0438 Naming Standards) don't surface as individually-named elementHeader
keys the way most classifications do (e.g. Confidentiality ->
elementHeader.confidentiality) -- they're bucketed into a single
list-valued elementHeader.glossaryTermKinds key instead, same shape
MetadataExpert.get_metadata_element_by_guid's top-level classifications
list already uses. Not a data-missing bug -- confirmed live the
classifications ARE present at every graphQueryDepth, just under a key a
naive dict-valued-classification extractor won't check. Not documented
anywhere in this codebase (get_term_by_guid currently has no docstring at
all) -- flagged as a follow-up docs fix, not attempted in this commit.

Signed-off-by: Dan Wolfson <dan.wolfson@pdr-associates.com>
…n Egeria server gap

_async_update_note built feedback-manager/notes/{noteGUID}, which 404s.
This URL was cross-checked against Egeria-api-feedback-manager.http's
updateNote worked example on three separate re-verification passes
(2026-08-05, 2026-08-15, 2026-08-18) and matched byte-for-byte each time --
which is exactly why this got classified as an Egeria server bug
(unregistered/unshipped endpoint) rather than a pyegeria bug. The .http
reference file itself was stale at the time, so "matches ground truth"
was false confidence: both sides of the comparison shared the same wrong
URL.

Fixed by dwolfson after refreshing the local Egeria-api-feedback-manager.http
copy -- its updateNote example now shows feedback-manager/assets/{noteGUID}
/update (the same assets/{guid}/update shape the feedback-manager service
uses elsewhere), not feedback-manager/notes/{noteGUID}. Corrected
_async_update_note's URL to match.

Verified live against qs-view-server: created a throwaway DataStructure ->
NoteLog -> Note (same repro every prior re-check used), called
update_note(guid, display_name=..., description=...) -- succeeded
(previously 404'd every time). Fetched the note back via
get_notes_for_note_log and confirmed both fields actually persisted, not
just a 200 with no real effect. 2 new unit tests
(test_update_note_url.py, mocked _async_make_request, no live server) lock
in the corrected URL and body shape.

PYEGERIA_ISSUES.md: moved ISSUE-30 to the resolved appendix, corrected its
Layer from Egeria Server to Pyegeria, and added a note for future
re-verifications -- "matches the .http ground truth" is only as
trustworthy as that file's own currency; worth being more skeptical of a
"must be server-side" verdict when the .http file hasn't been
independently re-verified against a current server/Swagger spec recently.

pytest tests/micro-tests/ passes in full.

Signed-off-by: Dan Wolfson <dan.wolfson@pdr-associates.com>
…tern

usage is a real DesignPatternProperties field (confirmed in
Egeria-api-solution-architect.http's createDesignPattern/
updateDesignPattern worked examples) that the "Design Pattern Base"
compact-spec bundle never declared -- unlike most gaps in this tracker,
this wasn't even a silent-drop: a ### Usage block would have failed
--validate outright as an undeclared attribute, not been misrouted once
supplied.

Added via the Dr.Egeria Spec Editor's REST API: "Usage" added to the
"Design Pattern Base" bundle's own_attributes, reusing the existing shared
Usage attribute definition already used elsewhere in this family (no new
attribute definition needed). Wired usage into
set_solution_architect_body()'s DesignPattern branch in
common_md_utils.py. refresh_specs regenerated both basic/advanced
templates; validate_compact_specs still reports 0 errors.

Verified live against qs-view-server: created a real DesignPattern with
Usage set, fetched it back, usage persisted correctly. 3 new unit tests
(test_design_pattern_usage.py, pure function test, no live server needed).
pytest tests/micro-tests/ passes in full.

Signed-off-by: Dan Wolfson <dan.wolfson@pdr-associates.com>
…guous ANY-lookup bug it was masking

ruff check flagged 10 findings in base_report_formats.py -- mostly cosmetic
import-ordering (E402, caused by a second unassigned string-literal
"documentation" block sitting between the real module docstring and the
actual imports; merged into one true docstring, imports consolidated) plus
one unnecessary f-string (F541). One finding was not cosmetic:

F811: select_report_spec was defined twice. The real ~70-line
implementation was silently shadowed by
`select_report_spec = select_report_format` near the bottom of the file (a
"Legacy names remain available (no change to behavior)" migration alias).

First attempt at deleting the shadowed dead function caused a false
alarm -- two pre-existing functional-test failures
(test_get_output_format_type_match, test_select_terms_formats) appeared
right after, but re-running them against the unmodified file confirmed
they failed identically before the change too. The dead-function deletion
was safe: select_report_format's registry-based logic is a confirmed
strict superset of the old body (same alias-matching + ANY/formats-lookup
logic, plus an extra TABLE->DICT fallback and question_spec the old body
lacked).

Investigating those 2 "unrelated" failures found a real bug they were
masking: get_report_spec_match's handling of a
select_report_spec(kind, "ANY") result does a reverse lookup by matching
heading+description text against every entry in report_specs -- ambiguous
whenever two FormatSets share identical heading/description. Confirmed
live: "Collections" and "BasicCollections" both use "Common Collection
Information"/"Attributes generic to all Collections." -- BasicCollections
has only an ALL-typed format, Collections has MERMAID/DICT/TABLE/
REPORT/ALL. Asking for TABLE on "Collections" silently resolved to
BasicCollections' narrow ALL format instead, no error. Separately,
test_select_terms_formats failed because select_report_spec("Terms",
"LIST") returned None -- no alias "Terms" existed for the renamed
"Glossary-Terms" FormatSet.

Fix: _select_from_registry now carries the resolved registry key through
in the "ANY" output dict as "_report_spec_name"; get_report_spec_match
prefers an exact lookup via that key over the ambiguous text match,
falling back to the old behavior only for a dict that lacks the key (e.g.
one loaded from a pre-fix save_report_specs() JSON file). Added "Terms" as
an explicit alias on the "Glossary-Terms" FormatSet.

Verified: both previously-failing tests now pass. 5 new unit tests
(test_report_spec_any_lookup.py) cover the resolved-name carry-through,
confirm the documented ambiguous pair still exists (so this test would
have caught the original bug), the correct-resolution path, the
legacy-fallback path, and the Terms alias. ruff check now reports zero
findings (was 10). Full pytest tests/micro-tests/ passes, plus every
functional test touching this module.

Also updated ISSUE-54's writeup: checked dwolfson's hypothesis that the
duplicate GUIDs found in the corrected pagination scan might just be
multiple versions of the same object -- ruled out definitively. Every
occurrence of every duplicated GUID (1,112 of them in this run) has the
identical version number and updateTime; 0 showed two different versions.
Rules out a versioning artifact, leaves unstable server-side result
ordering (the original 2026-08-06 hypothesis) as the best-supported
explanation.

Signed-off-by: Dan Wolfson <dan.wolfson@pdr-associates.com>
…he real mechanism

dwolfson asked how a duplicate GUID is even possible if the repository
enforces uniqueness. Ruled out every "actually fine" explanation with
direct evidence:

- Not a live-mutating dataset: native count stayed exactly stable
  (11,079 -> 11,079) across a full 7.4s/23-page scan; page 1 was
  byte-for-byte identical before and after; two immediate back-to-back
  identical requests returned the same elements in the same order.
- Not a simple page-boundary tie-break: only 245/1,619 (15%) of duplicate
  occurrences were in adjacent pages; 1,374 (85%) spanned 2+ pages apart,
  max observed gap 10 pages (~5,000 elements). Rules out an off-by-a-few
  boundary artifact.
- Best-supported mechanism: findMetadataElements on a broad Referenceable
  scan likely sorts without a unique tiebreaker (e.g. GUID) in the
  effective ORDER BY. The two most-duplicated types (ValidMetadataValue,
  SpecificationPropertyValue -- 959 of 1,112 duplicates) are both
  bulk-loaded from an archive, plausibly sharing identical creation
  timestamps at scale. Each startFrom/pageSize call is a fresh query
  execution, not a stable cursor, so ties can resolve differently between
  calls -- the classic OFFSET/LIMIT-without-fully-unique-ORDER-BY SQL
  pagination anti-pattern, server-side in Egeria's repository query, not a
  real repository-level duplicate GUID and not a pyegeria bug.

Signed-off-by: Dan Wolfson <dan.wolfson@pdr-associates.com>
…g sequencingProperty=GUID/qualifiedName

Direct test of dwolfson's theory: force a deterministic sort by a genuinely
unique property and see whether duplicates disappear.

- Baseline (no sequencing): 853 duplicates, 9,752/10,605 distinct (92%).
- sequencingProperty=GUID: duplicates collapse to 1 (plausibly one live
  edit mid-scan, not a leftover tie).
- sequencingProperty=qualifiedName: duplicates collapse to 0 -- confirms
  the theory outright.

But the qualifiedName-sorted scan surfaced a second, related defect:
completeness was still only 10,597/11,081 (95.6%), and the omission wasn't
random -- concentrated entirely in ValidMetadataValue (211 missing of
2,296) and PersonRole (63 missing of 334), every other type exact. Root
cause: every single element of both types has qualifiedName=None (confirmed
2,296/2,296 and 323/323), so sorting by qualifiedName ties them all
together into one giant unresolved group at the null position -- the same
missing-tiebreaker defect, just manifesting as omission instead of
duplication when the chosen sort property is itself null for an entire
type. GUID is the objectively safer workaround since it's guaranteed
non-null and unique for every element regardless of type.

Completeness under GUID sequencing not yet measured -- session was blocked
mid-check by an unrelated concurrent edit breaking pyegeria's import chain
(pyegeria/omvs/feedback_manager.py syntax error), not touched by this
investigation.

Signed-off-by: Dan Wolfson <dan.wolfson@pdr-associates.com>
_async_new_relationship_request discarded the GUID Egeria's
relationship-create endpoints return ({"class": "GUIDResponse", "guid":
"..."}), so every _async_link_X wrapper built on this shared helper was
silently unable to report the new relationship's own identity. This
matters most for MULTI_LINK relationship types (per
ValidMetadataManager.get_all_relationship_defs()'s relationshipCategory
field), where more than one relationship instance of the same type can
exist between the same pair of elements -- the GUID is the only way to
target a specific instance later via Update/Detach.

- _async_new_relationship_request now returns Optional[str] (the GUID),
  extracted from the response in all three code paths. Purely additive:
  existing callers that ignore the return value are unaffected.
- _async_link_solution_linking_wire / link_solution_linking_wire (sync)
  now return the new SolutionLinkingWire's GUID.
- SolutionLinkProcessor.apply_changes()'s brand-new-wire-create branch
  now captures that GUID into parsed_output["guid"] and displays it in
  the result markdown ("Created wire {guid} ..."), matching the sibling
  "Updated wire {guid} ..." branch instead of falling through to a
  generic message with no GUID shown.

LineageLinker's _async_link_lineage/_async_link_data_flow already
returned the GUID correctly (bypassing the broken shared helper) and
needed no change.

Note: SolutionLinkingWire is UNI_LINK in the live type registry despite
being treated as multi-link by existing code comments (Egeria PR #9156).
Per user direction, relationshipCategory is the source of truth going
forward; reconciling that discrepancy is left as a follow-up.

Signed-off-by: Dan Wolfson <dan.wolfson@pdr-associates.com>
New pyegeria/core/relationship_multiplicity.py: async_is_multi_link() /
async_get_relationship_category() query ValidMetadataManager's
get_all_relationship_defs()'s relationshipCategory field
(MULTI_LINK/UNI_LINK/REVERSIBLE) to determine whether a relationship
type allows more than one instance between the same pair of elements --
the real, live-queryable signal (there is no literal "multi-link"
boolean field in Egeria's type-def JSON).

Results are cached per (platform_url, view_server) since type defs are
effectively static for a session; refresh=True bypasses the cache.
Unknown type names default to "not multi-link" (fall back to the
historical pair-based semantics) rather than raising.

Live-verified against a running server: DataFlow=MULTI_LINK,
SolutionLinkingWire=UNI_LINK, GovernedBy=UNI_LINK, Synonym=REVERSIBLE --
matches the investigation from the prior commit exactly, including the
confirmed SolutionLinkingWire discrepancy (UNI_LINK in the live registry
despite being treated as multi-link by existing Dr.Egeria code per
Egeria PR #9156; relationshipCategory is the source of truth going
forward per user direction).

This is the detection primitive other _async_link_X GUID-return/display
work (the ~20 other MULTI_LINK types) will build on next; no callers
wired up yet.

Signed-off-by: Dan Wolfson <dan.wolfson@pdr-associates.com>
…NK create paths (ISSUE-68)

Audited every _async_link_X wrapper for the 21 relationship types Egeria
flags as relationshipCategory=MULTI_LINK (via the new
pyegeria.core.relationship_multiplicity utility). Types where an OMVS
create-relationship wrapper exists and Update/Detach already require a
relationship GUID (not just the pair of element GUIDs) had their GUID
silently discarded on create, same gap as SolutionLinkingWire (prior
commit):

- collection_manager.py: _async_link_agreement_actor / link_agreement_actor,
  _async_link_agreement_item / link_agreement_item -- now return the new
  AgreementActor/AgreementItem relationship's GUID.
- asset_maker.py: _async_add_catalog_target -- was already documented as
  returning a GUID but had a placeholder `"Relationship created"` string;
  now actually returns it (the shared helper fix from the prior commit
  makes this possible).
- external_links.py: _async_link_external_reference, _async_link_media_reference,
  _async_link_cited_document (+ sync wrappers) -- now return their new
  relationship's GUID.
- action_author.py: _async_setup_next_action_process_step /
  setup_next_action_process_step -- now returns the new
  NextGovernanceActionProcessStep relationship's GUID (Update/Detach
  already took relationship_guid).
- reference_data.py: _async_link_valid_value_implementation /
  link_valid_value_implementation -- now returns the GUID, with a
  docstring note that Egeria's own REST API for this relationship
  (Egeria-api-reference-data.http) has no relationship-guid-targeted
  detach endpoint, unlike the others, so the GUID is currently only
  useful for record-keeping.
- md_processing/v2/governance.py (GovernanceLinkProcessor.apply_changes):
  the Certification/License/Agreement T&C create branches now capture
  the GUID returned by _async_add_certification_to_element /
  _async_add_license_to_element / _async_link_agreement_item into
  parsed_output["guid"] and display it in the result markdown, instead
  of falling through to a generic "Operation completed." with no GUID
  shown -- the same processor's own Detach branch already raises
  ValueError without this GUID, so users previously had no way to get it
  short of a separate find.

Types considered but left unchanged: Certification/License's OMVS
methods (classification_explorer.py's _async_add_certification_to_element
/ _async_add_license_to_element, governance_officer.py's
_async_license_element / _async_certify_element) already returned the
GUID correctly -- only the Dr.Egeria processor was discarding it.
CatalogTarget, NextGovernanceActionProcessStep already had GUID-based
Update/Detach on the OMVS side, confirming the same "GUID exists,
wasn't surfaced on create" pattern each time. AssociatedSecurityList,
DataLineageRelationship, NetworkGatewayLink, SupportedGovernanceService
have no OMVS wrapper at all (not implemented) -- nothing to fix there.

New tests: test_governance_link_multilink_guid.py.

Signed-off-by: Dan Wolfson <dan.wolfson@pdr-associates.com>
Documents both commits of the multi-link relationship work: the
_async_new_relationship_request GUID-return fix, the new
relationship_multiplicity detection utility, and the audit/fix of every
MULTI_LINK type's create-path GUID surfacing across pyegeria and
Dr.Egeria's GovernanceLinkProcessor/SolutionLinkProcessor.

Signed-off-by: Dan Wolfson <dan.wolfson@pdr-associates.com>
@dwolfson
dwolfson merged commit ef15b2d into odpi:main Aug 18, 2026
1 check passed
dwolfson added a commit to dwolfson/trellis that referenced this pull request Aug 18, 2026
… drop pyegeria ISSUE-63 workaround

Rename (per direct request, following the 'Scouting - Full Survey' naming
convention already used elsewhere): docs/dr-egeria/repo_survey_types.csv's
survey_display_name updated, doc regenerated, executed live against Egeria
as an in-place "Update Governance Action Process" (qualified_name
GovActionProcess::RepoFullSurvey unchanged, GUID confirmed identical
before/after). Only the process-rename block was re-executed, not the full
17-step doc, to avoid re-triggering Dr.Egeria's known Link Next Process
Step non-idempotency issue.

ISSUE-63 (egeria-python PYEGERIA_ISSUES.md) is fixed upstream: pyegeria's
MetadataExpert.delete_related_elements() now routes through
DeleteRelationshipRequestBody (which declares deleteMethod) instead of the
old OpenMetadataDeleteRequestBody (which silently dropped it). Confirmed
live against a real Egeria server with pyegeria installed from the fix
commit (dwolfson/egeria-python@b765eaa, PR odpi/egeria-python#275, not yet
merged/released). SurveyDefinitionReader.reconcile_step_links() reverted
from the raw _async_make_request transport-bypass workaround back to
calling delete_related_elements() directly with an explicit deleteMethod —
the clean, intended call shape. Test fake updated to match (mocks
delete_related_elements() again, not the private transport method).

Caveat: this fix is only live in the current venv via a manual
`uv pip install --no-deps` override from the PR branch — pyproject.toml/
uv.lock still pin pyegeria>=6.0.16.17 (resolves to 6.0.17.17, the old
unfixed version), so a `uv sync`/`uv run`-triggered resync will silently
revert to the broken behavior until PR #275 merges, ships in a real
pyegeria release, and this repo's floor is bumped + `uv lock
--upgrade-package pyegeria` is run (same pattern pyproject.toml already
notes for ISSUE-56/pyegeria>=6.0.18.1).

Full suite: 1232 passed, 9 skipped.

Signed-off-by: Dan Wolfson <dan.wolfson@pdr-associates.com>
dwolfson added a commit to dwolfson/trellis that referenced this pull request Aug 18, 2026
…ess_graph rename

pyegeria's upcoming release (PR odpi/egeria-python#275, same PR fixing
ISSUE-63's deleteMethod bug) renames GovernanceOfficer's
get_governance_process_graph to get_governance_action_process_graph.
Updated SurveyDefinitionReader.fetch()/reconcile_step_links() and their
test fakes/comments to the new name — confirmed live against a real
Egeria server (fetch() correctly returns "Scouting - Full Survey" with
all 17 steps; reconciler dry-run reports all 4 Survey Definitions clean).

pyproject.toml's pyegeria comment expanded to note both requirements
(this rename + ISSUE-63) and that the floor needs bumping once the real
release ships.

Full suite: 1232 passed, 9 skipped.

Signed-off-by: Dan Wolfson <dan.wolfson@pdr-associates.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant