From 39ddc896b11143e1904e8f8a8e14424656a117ac Mon Sep 17 00:00:00 2001 From: Dan Wolfson Date: Sun, 6 Sep 2026 17:12:39 -0500 Subject: [PATCH 1/4] docs(PYEGERIA_ISSUES): log ISSUE-91 -- mcp dependency floor too loose pyproject.toml declares mcp >=0.1 but pyegeria/core/mcp_server.py imports mcp.server.mcpserver.MCPServer, which requires mcp>=2.0 (confirmed live: this dev venv has mcp==2.0.0 installed and the import works; the module path doesn't exist in the 0.x/1.x mcp package line). Found by Egeria Advisor rebuilding its demo deployment against pyegeria 6.1.10 -- worked fine because they pinned mcp==2.1.1 explicitly, not because pyegeria's own floor would have caught an older mcp. Signed-off-by: Dan Wolfson --- PYEGERIA_ISSUES.md | 75 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/PYEGERIA_ISSUES.md b/PYEGERIA_ISSUES.md index 3ea041a8..a79e2a85 100644 --- a/PYEGERIA_ISSUES.md +++ b/PYEGERIA_ISSUES.md @@ -199,6 +199,50 @@ security context changes; (2) quickstart content: give `generalnpa` read access elements its engine actions anchor to, or anchor those actions to elements the engine-host identity can read. Full draft: trellis session scratch `egeria-issue-engine-host-403-loop.md`. +### ISSUE-91: `pyegeria.core.mcp_server` imports `mcp.server.mcpserver` (mcp 2.x only) but `pyproject.toml` declares `mcp >=0.1` — any consumer that resolves mcp 1.x gets a server that dies at import + +**Layer:** pyegeria packaging · **Status:** open · **Found:** 2026-09-05 (Egeria Advisor dev startup on the M3 Max) + +Commit 2b39ba06 (2026-07-30, "migrate mcp_server.py to mcp 2.0.0's MCPServer") changed the +server's import to: + +```python +from mcp.server.mcpserver import MCPServer +``` + +That module exists only in `mcp >= 2.0.0` (1.x ships `mcp.server.fastmcp` instead). The +dependency declaration was not updated and still reads `"mcp >=0.1"` — verified in the released +6.1.5 wheel's METADATA (`Requires-Dist: mcp>=0.1`) and in the current `pyproject.toml` at 6.1.10. + +**How it shows up.** trellis pinned `mcp>=1.0.0` and its lock resolved mcp 1.29.0, which satisfies +pyegeria's declared range. Launching the server then fails before it can speak MCP: + +``` +$ python -m pyegeria.core.mcp_server +MCP import failed. + File ".../pyegeria/core/mcp_server.py", line 24, in + from mcp.server.mcpserver import MCPServer +ModuleNotFoundError: No module named 'mcp.server.mcpserver' +``` + +A client sees only "No response from MCP server" because the traceback goes to stderr and the +process exits without writing a JSON-RPC frame. With mcp 2.1.1 installed the same command answers +`initialize` normally (`serverInfo.name = "pyegeria-mcp"`). + +**Why it went unnoticed.** The quickstart containers run mcp 2.1.1 (pyegeria 6.1.9) and use their own +`/app/mcp_server.py` mounted over SSE in `pyegeria_handler`, not this stdio module, so the +egeria-workspaces path never exercised it. The egeria-python checkout's own venv also has mcp 2.0.0. + +**Proposed fix (backward compatible for callers).** In `pyproject.toml` declare `"mcp >=2.0"`. Nothing +else needs to change: the import is already 2.x-only, so raising the floor only turns a runtime +import crash into a resolver error at install time. If 1.x support is wanted instead, gate the +import (`try: from mcp.server.mcpserver import MCPServer except ImportError: from mcp.server.fastmcp +import FastMCP as MCPServer`) — but the 2.x API differs beyond the class name, so the floor bump is +the honest option. + +**Consumer-side workaround applied in trellis (8441efb):** both packages now declare `mcp>=2.0.0` +and the lock carries mcp 2.1.1, matching the quickstart containers. + ### ISSUE-38 (PY-18): `count_relationships_between_elements("Exception")` (276) disagrees with `ClassificationExplorer.get_relationships("Exception")` (55) **Update 2026-08-30, from the Egeria team (Mandy Chessell).** Leaving this @@ -751,6 +795,37 @@ on an Egeria Server capability that doesn't exist yet — but the pyegeria/ Dr.Egeria-side work each will need once that capability ships is written into the entry now, so it isn't rediscovered from scratch later. +### ISSUE-91: `pyproject.toml` declares `mcp >=0.1`, but `pyegeria.core.mcp_server` needs `mcp>=2.0` — the declared floor lets a resolver install a version too old to import the module at all + +**Layer:** Pyegeria · **Status:** open · **Found:** 2026-09-06 (Egeria Advisor, containerized demo deployment rebuild against pyegeria 6.1.10). + +`pyproject.toml`'s `[project.dependencies]` declares `"mcp >=0.1"`, but +`pyegeria/core/mcp_server.py` imports `from mcp.server.mcpserver import +MCPServer` — confirmed live in this checkout's dev venv: +`importlib.metadata.version("mcp")` is `2.0.0`, and +`mcp.server.mcpserver.MCPServer` only exists at that version; the module +path is new to the 2.x line, not present in the 0.x/1.x `mcp` package +history. A resolver that's free to pick anything satisfying `>=0.1` (no +upper or tighter lower bound forcing 2.x) can legitimately land on a much +older `mcp` release, at which point `import pyegeria.core.mcp_server` +fails outright rather than degrading gracefully. + +**Why it matters, found how:** a container rebuild of Egeria Advisor's +demo deployment against pyegeria 6.1.10 pinned `mcp==2.1.1` explicitly +(not resolved from pyegeria's own floor) and confirmed EA's MCP agent +pre-warms cleanly on it — so 6.1.10 itself works fine when the caller +pins a modern `mcp`, but nothing in pyegeria's own declared dependency +would have caught a caller who didn't. + +**Ask:** tighten `pyproject.toml`'s `mcp` constraint to actually match +what `mcp_server.py` requires (`mcp>=2.0` at minimum — confirm the exact +version `MCPServer`/`mcp.server.mcpserver` was introduced at, and pin to +that) rather than the inherited placeholder `>=0.1` floor. Not +independently verified against the `mcp` package's own changelog/git +history here — the live import check above shows 2.0.0 works and the +module path is absent from the 0.x/1.x line by inspection, but the exact +first-working version wasn't pinned down. + ### ISSUE-87: `ClassificationExplorer.add_ownership_to_element`'s docstring sample body says `"class": "OwnerProperties"` — the method itself only accepts `"OwnershipProperties"`, so the documented body cannot be sent **Layer:** Pyegeria · **Status:** fixed 2026-09-05 (Pyegeria — From 09b80c4d0eceb67d845d21b37d186a8247623937 Mon Sep 17 00:00:00 2001 From: Dan Wolfson Date: Sun, 6 Sep 2026 20:53:10 -0500 Subject: [PATCH 2/4] test(view): cover ISSUE-86's caller-held bearer token in exec_report_spec MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit format_set_executor.py's `token` parameter (ISSUE-86 — let a caller that already holds an Egeria bearer token run a report without a password) is on main with no dedicated test. These tests existed only on an unpushed local branch, claude/cranky-chebyshev-be2494, alongside a second, parallel implementation of the same feature that main had meanwhile gained by another route. Pushing that branch would have added a duplicate implementation; the tests were the part worth keeping, so they are salvaged here on their own. They were written against that branch's `_authenticate_client()` helper, which main does not have — verified they pass unchanged against main's inline implementation (7 passed), so they test the behaviour rather than that refactor's shape. Co-Authored-By: Claude Opus 5 Signed-off-by: Dan Wolfson --- .../test_format_set_executor_token.py | 161 ++++++++++++++++++ 1 file changed, 161 insertions(+) create mode 100644 tests/micro-tests/test_format_set_executor_token.py diff --git a/tests/micro-tests/test_format_set_executor_token.py b/tests/micro-tests/test_format_set_executor_token.py new file mode 100644 index 00000000..d4ea5360 --- /dev/null +++ b/tests/micro-tests/test_format_set_executor_token.py @@ -0,0 +1,161 @@ +"""ISSUE-86: `exec_report_spec(..., token=...)` must authenticate the client it +builds with `set_bearer_token(token)` instead of minting one from +user/user_pass, on BOTH client-building paths (the format-row/find path and +the analytic_function path). With no token, behaviour is unchanged +(`create_egeria_bearer_token()`).""" +import pytest + +from pyegeria.view import format_set_executor as fse +from pyegeria.core import mcp_adapter + + +class _RecordingClient: + """Stands in for any OMVS client class the executor instantiates.""" + instances: list = [] + + def __init__(self, view_server, view_url, user_id=None, user_pwd=None, **kw): + self.view_server = view_server + self.platform_url = view_url + self.user_id = user_id + self.user_pwd = user_pwd + self.token = None + self.calls: list[str] = [] + _RecordingClient.instances.append(self) + + def create_egeria_bearer_token(self, *a, **kw): + self.calls.append("create") + self.token = "minted" + return self.token + + def set_bearer_token(self, token): + self.calls.append("set") + self.token = token + + def find_things(self, **kwargs): + return [{"guid": "1", "displayName": "x"}] + + +@pytest.fixture(autouse=True) +def _reset_instances(): + _RecordingClient.instances = [] + yield + _RecordingClient.instances = [] + + +_FIND_FMT = { + "action": { + "function": "Fake.find_things", + "required_params": [], + "optional_params": [], + "spec_params": {}, + }, + "target_type": "Referenceable", +} + +_ANALYTIC_FMT = { + "action": {"analytic_function": "fake.analytic", "analytic_spec_params": {}}, + "target_type": "Referenceable", +} + + +def _patch_find_path(monkeypatch): + monkeypatch.setattr(fse, "select_report_spec", lambda name, out: _FIND_FMT) + monkeypatch.setattr(fse, "get_report_registry", lambda: {}) + monkeypatch.setattr(fse, "_resolve_client_and_method", + lambda decl: (_RecordingClient, "find_things")) + + +def _patch_analytic_path(monkeypatch): + def _analytic(client): + return {"count": 3, "token_seen": client.token} + monkeypatch.setattr(fse, "select_report_spec", lambda name, out: _ANALYTIC_FMT) + monkeypatch.setattr(fse, "get_report_registry", lambda: {}) + monkeypatch.setattr(fse, "_resolve_analytic_function", lambda decl: _analytic) + monkeypatch.setattr(fse, "EgeriaTech", _RecordingClient) + + +# --- format-row (find_method) path ------------------------------------------- + +def test_find_path_with_token_uses_set_bearer_token(monkeypatch): + _patch_find_path(monkeypatch) + result = fse.exec_report_spec( + "Anything", output_format="DICT", view_server="vs", view_url="https://x", + user="svc", user_pass="svc-pw", token="user-token", + ) + assert result["kind"] == "json" + (client,) = _RecordingClient.instances + assert client.calls == ["set"] + assert client.token == "user-token" + + +def test_find_path_without_token_mints_bearer_token(monkeypatch): + _patch_find_path(monkeypatch) + result = fse.exec_report_spec( + "Anything", output_format="DICT", view_server="vs", view_url="https://x", + user="svc", user_pass="svc-pw", + ) + assert result["kind"] == "json" + (client,) = _RecordingClient.instances + assert client.calls == ["create"] + assert client.user_id == "svc" and client.user_pwd == "svc-pw" + + +# --- analytic_function path --------------------------------------------------- + +def test_analytic_path_with_token_uses_set_bearer_token(monkeypatch): + _patch_analytic_path(monkeypatch) + result = fse.exec_report_spec( + "Anything", output_format="DICT", view_server="vs", view_url="https://x", + user="svc", user_pass="svc-pw", token="user-token", + ) + assert result == {"kind": "json", "data": {"count": 3, "token_seen": "user-token"}} + (client,) = _RecordingClient.instances + assert client.calls == ["set"] + + +def test_analytic_path_without_token_mints_bearer_token(monkeypatch): + _patch_analytic_path(monkeypatch) + result = fse.exec_report_spec( + "Anything", output_format="DICT", view_server="vs", view_url="https://x", + user="svc", user_pass="svc-pw", + ) + assert result["data"]["token_seen"] == "minted" + (client,) = _RecordingClient.instances + assert client.calls == ["create"] + + +def test_chart_path_threads_token(monkeypatch): + """SERIES/BAR/PIE dispatch to _exec_analytic_chart before the Format-row + lookup -- the token must survive that hop too.""" + _patch_analytic_path(monkeypatch) + monkeypatch.setattr(fse, "get_report_spec_heading", lambda name: "H", raising=False) + fse.exec_report_spec( + "Anything", output_format="BAR", view_server="vs", view_url="https://x", + user="svc", user_pass="svc-pw", token="user-token", + ) + (client,) = _RecordingClient.instances + assert client.calls == ["set"] + assert client.token == "user-token" + + +# --- MCP adapter passthrough -------------------------------------------------- + +def test_mcp_run_report_forwards_token(monkeypatch): + seen = {} + + def _fake_exec(**kwargs): + seen.update(kwargs) + return {"kind": "empty"} + + monkeypatch.setattr(mcp_adapter, "exec_report_spec", _fake_exec) + mcp_adapter.run_report(report="R", user="u", user_pass="p", token="tok") + assert seen["token"] == "tok" + assert seen["user"] == "u" and seen["user_pass"] == "p" + + +def test_mcp_run_report_default_token_is_none(monkeypatch): + seen = {} + monkeypatch.setattr(mcp_adapter, "exec_report_spec", + lambda **kw: seen.update(kw) or {"kind": "empty"}) + mcp_adapter.run_report(report="R", user="u", user_pass="p") + assert seen["token"] is None From 3ca07ba725c780ca9987d9692afcd7a68425e6d9 Mon Sep 17 00:00:00 2001 From: Dan Wolfson Date: Mon, 7 Sep 2026 20:12:29 -0500 Subject: [PATCH 3/4] ISSUE-92: Project Type's description lists 4 of its 6 valid_values MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commands_project_compact.json's `Project Type` attribute declares six valid_values (Project, Campaign, Task, PersonalProject, StudyProject, Experiment) and describes four — `Project`, which is also the attribute's own default_value, and `Experiment` are both missing from the prose. The machine-readable list is correct: it matches Egeria 6's Project classifications in OpenMetadataType.java (model 0130). Only the description is behind. It has propagated. gen_md_cmd_templates and gen_dr_help render the description, so 25 files in the main tree carry the sentence verbatim — the source JSON plus 24 generated artifacts, 16 of which ship as user-facing templates. Notably sample-data/templates/{basic,advanced}/Projects/Create_Experiment.md tells the reader Experiment is not a supported value, and the generated help tables contradict themselves in a single row by printing the prose beside the valid_values column. Logged, not fixed, per the standing rule for this repo. The entry carries a suggested replacement description worded from the Egeria type definitions themselves, the regenerate-and-propagate steps, and a note to check whether any other compact-command attribute enumerates its valid_values in prose — the same latent defect wherever it exists. Found while mapping Resource Explorer's investigation classifications onto Egeria's. Co-Authored-By: Claude Opus 5 Signed-off-by: Dan Wolfson --- PYEGERIA_ISSUES.md | 87 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/PYEGERIA_ISSUES.md b/PYEGERIA_ISSUES.md index a79e2a85..d2e3ae70 100644 --- a/PYEGERIA_ISSUES.md +++ b/PYEGERIA_ISSUES.md @@ -199,6 +199,93 @@ security context changes; (2) quickstart content: give `generalnpa` read access elements its engine actions anchor to, or anchor those actions to elements the engine-host identity can read. Full draft: trellis session scratch `egeria-issue-engine-host-403-loop.md`. +### ISSUE-92: `Project Type`'s description in `commands_project_compact.json` lists only 4 of its 6 `valid_values` — omits `Project` and `Experiment`, and the stale text is baked into 24 generated files + +**Layer:** Pyegeria · **Status:** open · **Found:** 2026-09-07 (Resource +Explorer, designing investigation → Egeria Project classification mapping). + +`md_processing/data/compact_commands/commands_project_compact.json`, the +`Project Type` attribute (`variable_name: project_type`): + +```json +"valid_values": [ + "Project", "Campaign", "Task", "PersonalProject", "StudyProject", "Experiment" +], +"description": "A string classifying the project. Supported values are Campaign, Task, PersonalProject and StudyProject." +``` + +`valid_values` has six entries; the description names four. `Project` (which +is also this attribute's own `default_value`) and `Experiment` are both +missing from the prose. The machine-readable list is correct — it matches +Egeria 6's actual Project classifications in +`OpenMetadataType.java` (0130): `CAMPAIGN_CLASSIFICATION`, +`TASK_CLASSIFICATION`, `PERSONAL_PROJECT_CLASSIFICATION`, +`STUDY_PROJECT_CLASSIFICATION`, `EXPERIMENT_CLASSIFICATION`. Only the +description is behind. + +**Why it matters more than one stale string:** the description is what +`gen_md_cmd_templates` and `gen_dr_help` render, so it has propagated. In +this checkout, 25 files in the main tree carry the sentence verbatim — the +one source JSON plus 24 generated artifacts: + +``` +md_processing/data/compact_commands/commands_project_compact.json <- source +md_processing/data/compact_commands_backup/commands_project_compact.json +sample-data/templates/{basic,advanced}/Projects/*.md (16) +sample-data/egeria-inbox/dr-egeria-help-*.md (7) +``` + +The sharpest symptom: **`sample-data/templates/{basic,advanced}/Projects/Create_Experiment.md` +tells the reader that `Experiment` is not a supported value** — on the +template whose entire purpose is to create one. `Create_Project.md` has the +same problem for `Project`. The generated help tables are self-contradictory +in a single row, because they print the prose and the `valid_values` list +side by side: + +``` +... Supported values are Campaign, Task, PersonalProject and StudyProject. | False | Project, Campaign, Task, PersonalProject, StudyProject, Experiment | Domain | +``` + +A reader who trusts the sentence over the column will never reach for +`Experiment`, which is the one classification carrying its own defining +attribute (`hypothesis`), so the omission suppresses a real capability +rather than just reading untidily. + +**Where seen:** found while mapping Resource Explorer's investigation +`project_classification` onto Egeria's Project classifications — the +description was the first thing read, and it made `Experiment` look +unsupported until `valid_values` and the Egeria type source were checked. + +**Candidate fix (one string, then regenerate):** edit the `description` in +`commands_project_compact.json` to cover all six, ideally naming what each +means rather than just listing them again — the `valid_values` array +already lists them, so prose that only repeats the list adds nothing and +will drift again the next time a value is added. Suggested: + +> "A string classifying the project. `Project` (the default) applies no +> classification. `Campaign` is a long-term strategic initiative delivered +> through multiple projects; `Task` a self-contained short activity; +> `PersonalProject` an informal project an individual creates to organize +> their own work; `StudyProject` a focused analysis of a topic, person, +> object or situation; `Experiment` a project testing a hypothesis, which +> is recorded in the `hypothesis` attribute." + +(Wording taken from the Egeria type definitions themselves so the two +cannot disagree.) + +Then re-run `refresh_specs`, `gen_md_cmd_templates` and `gen_dr_help` per +the Dr.Egeria command-sync flow and propagate the regenerated templates/help +to `egeria-workspaces` and `egeria-advisor` — the 24 generated files above +will not update on their own, and 16 of them ship as user-facing templates. + +**Worth checking while in there:** whether any other compact-command +attribute has a `description` that enumerates its `valid_values` in prose. +Any such pair is the same latent defect — two lists that must be edited +together with nothing enforcing it. A cheap guard would be a spec-validation +check that flags a `description` naming a subset of its own `valid_values`. + +--- + ### ISSUE-91: `pyegeria.core.mcp_server` imports `mcp.server.mcpserver` (mcp 2.x only) but `pyproject.toml` declares `mcp >=0.1` — any consumer that resolves mcp 1.x gets a server that dies at import **Layer:** pyegeria packaging · **Status:** open · **Found:** 2026-09-05 (Egeria Advisor dev startup on the M3 Max) From 38d9be28dc1586cfa1232f05be905b523d2c5e2f Mon Sep 17 00:00:00 2001 From: Dan Wolfson Date: Tue, 8 Sep 2026 11:11:47 -0500 Subject: [PATCH 4/4] feat(pyegeria,dr-egeria): add Data Standards types (Egeria PR #9300) Adds SDK and Dr.Egeria support for the new Data Standards types: - pyegeria: Investigation classification pair on ProjectManager (set/clear_project_as_investigation), NamingStandardsVocabulary classification pair on GlossaryManager (set/clear_glossary_as_naming_standards_vocabulary), and the four new DataScope/DataLens datetime properties (dataValidityStartTime/EndTime, dataCoverageStartTime/EndTime) documented in classification_explorer.py and governance_officer.py sample bodies. - Dr.Egeria: registered Investigation/NamingStandardsVocabulary in curation.py's CLASSIFICATION_METHODS/CURATION_CLASSIFICATION_CLIENTS, added the 4 new Classify/Declassify commands to commands_curation_compact.json via the Spec Editor's REST API, and regenerated basic/advanced templates via refresh_specs. - docs/dr_egeria_manual.md updated to document the additions. Endpoint/property shapes were taken directly from the egeria PR #9300 diff on GitHub, since this checkout's `.http` ground truth files haven't been updated for this PR yet. validate_compact_specs currently fails its live-server OM_TYPE check for both new types since the server doesn't have the type archive deployed yet -- re-verify once it does. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01KYNxABE3SRUT5cXbpmrfU2 Signed-off-by: Dan Wolfson --- docs/dr_egeria_manual.md | 1 + .../commands_curation_compact.json | 90 +++++++++++ md_processing/v2/curation.py | 14 ++ pyegeria/core/_globals.py | 2 +- pyegeria/omvs/classification_explorer.py | 16 ++ pyegeria/omvs/glossary_manager.py | 153 ++++++++++++++++++ pyegeria/omvs/governance_officer.py | 8 + pyegeria/omvs/project_manager.py | 34 +++- .../Curation/Classify_Investigation.md | 98 +++++++++++ .../Classify_Naming_Standards_Vocabulary.md | 98 +++++++++++ .../Curation/Declassify_Investigation.md | 86 ++++++++++ .../Declassify_Naming_Standards_Vocabulary.md | 86 ++++++++++ .../basic/Curation/Classify_Investigation.md | 22 +++ .../Classify_Naming_Standards_Vocabulary.md | 22 +++ .../Curation/Declassify_Investigation.md | 22 +++ .../Declassify_Naming_Standards_Vocabulary.md | 22 +++ 16 files changed, 772 insertions(+), 2 deletions(-) create mode 100644 sample-data/templates/advanced/Curation/Classify_Investigation.md create mode 100644 sample-data/templates/advanced/Curation/Classify_Naming_Standards_Vocabulary.md create mode 100644 sample-data/templates/advanced/Curation/Declassify_Investigation.md create mode 100644 sample-data/templates/advanced/Curation/Declassify_Naming_Standards_Vocabulary.md create mode 100644 sample-data/templates/basic/Curation/Classify_Investigation.md create mode 100644 sample-data/templates/basic/Curation/Classify_Naming_Standards_Vocabulary.md create mode 100644 sample-data/templates/basic/Curation/Declassify_Investigation.md create mode 100644 sample-data/templates/basic/Curation/Declassify_Naming_Standards_Vocabulary.md diff --git a/docs/dr_egeria_manual.md b/docs/dr_egeria_manual.md index d36f19cc..5ac6f3ba 100644 --- a/docs/dr_egeria_manual.md +++ b/docs/dr_egeria_manual.md @@ -247,6 +247,7 @@ Dr.Egeria organizes its commands into "families," each corresponding to a specif - **Curation**: Apply classifications and relationships to *existing* Referenceable elements after the fact — this family creates no elements of its own, it curates ones created elsewhere. Every command names a `Target Element` (Reference Name) and either a classification level/status or a second element to relate to. - **Classifications** (`Classify`/`Reclassify`/`Declassify`, or `Classify`/`Update`/`Declassify` for the three multi-value ones): Impact, Confidence, Confidentiality, Criticality, Retention, Ownership, Digital Resource Origin, Zone Membership, Security Tags, Data Scope, Governance Expectations, Governance Measurements, Known Duplicate, Consolidated Duplicate, and the 0438 naming-standards markers Class Word, Modifier, Prime Word (added 2026-08-09 once Egeria PR #9166 shipped the backing `glossary-manager` endpoints — routed through `GlossaryManager`, not `ClassificationExplorer`, unlike every other classification here). Also, added 2026-08-21 once an `omvs_audit.py` gap-closure pass shipped their backing REST endpoints (all confirmed against a live 6.2-SNAPSHOT server): the 10 governance-point classifications (0435: Control/Verification/Enforcement/Execution Point, Policy Administration/Decision/Enforcement/Information/Management/Retrieval Point — routed through `GovernanceOfficer`), 6 metamodel markers (0463: Incomplete, ObjectIdentifier, ReferenceData, MobileResource, InstanceMetadata, MetamodelInstance — routed through `ClassificationExplorer`), ProjectKind (routed through `ProjectManager`), CollectionKind (routed through `CollectionManager`), and a Data Sharing Agreement retrofit pair for classifying/declassifying an already-existing Agreement (routed through `DigitalBusiness` — `Create Data Sharing Agreement`, Digital Products family, already sets this at creation time via `initialClassifications`). - **Relationships** (`Link`/`Unlink`, or `Attach`/`Update`/`Detach` for Search Keyword): Search Keyword, Semantic Assignment, Semantic Definition, Link Element To Scope (`ScopedBy`), Link Resource To Element (`ResourceList`), Link More Information, Peer Duplicate, Consolidated Duplicate Link. + - Investigation (0130 ProjectKind, routed through `ProjectManager`) and NamingStandardsVocabulary (0438, routed through `GlossaryManager`) — new Data Standards types from Egeria PR #9300, added 2026-09-08. **Not yet verified against a live server**: the type isn't deployed there yet (`validate_compact_specs` fails its OM_TYPE-against-live-server check for both until the server picks up the new archive), and this checkout's `.http` ground truth files haven't been updated for this PR either — re-verify (including `validate_compact_specs`) once both are current. - No classification in this family remains genuinely unimplemented as of 2026-08-21 — Policy Management Point (previously blocked on a missing pyegeria SDK method) is now registered along with the 9 sibling governance-point classifications above. - `Update Search Keyword`/`Detach Search Keyword` (fixed 2026-08-21) act on the `SearchKeyword` entity's own GUID via a new `Search Keyword GUID` attribute (`_async_update_search_keyword`/`_async_remove_search_keyword_from_element` both take only that GUID, not the `Target Element` the keyword is attached to — the `remove` method deletes the keyword entity itself despite its name). `Attach Search Keyword` (create + attach in one call) keeps its own `Target Element`-based bundle unchanged; `Update`/`Detach` each got their own dedicated bundle rather than sharing `Attach`'s, since `Target Element`/`Keyword` are separately mandatory attributes that don't apply to identifying an existing keyword by GUID. Live-verified end to end against a running 6.2-SNAPSHOT server, including a real bug this caught: `CurationLinkProcessor`/`CurationClassifyProcessor` never overrode `supports_target_element_lookup()`, so the base class's Create↔Update upsert-transition logic silently rewrote every `Update X` command in this family (including the pre-existing `Update Data Scope`/`Update Governance Expectations`/`Update Governance Measurements`) to `Create X` before it reached the processor's own verb-branching logic — for Search Keyword this meant `Update` silently deleted the entity instead of updating it. Both processors now override that method; see the commit fixing it for the full live-verification trail. - Two related commands live in *other* families' compact specs (via the shared `Person Action Base` bundle), routed to those families' own processors rather than `CurationClassifyProcessor`/`CurationLinkProcessor`: `Create Meeting` (Project family, via `my_profile.create_meeting`) and `Create ToDo` (Actor Manager family, via `my_profile.create_my_todo`). `Create Review` (Feedback family, via `my_profile.create_review`) and `Create Note` are also `Person Action Base` commands but documented under **Feedback** below, since that's their family. diff --git a/md_processing/data/compact_commands/commands_curation_compact.json b/md_processing/data/compact_commands/commands_curation_compact.json index 1dd175d3..ee9128eb 100644 --- a/md_processing/data/compact_commands/commands_curation_compact.json +++ b/md_processing/data/compact_commands/commands_curation_compact.json @@ -3302,6 +3302,20 @@ "own_attributes": [ "Search Keyword GUID" ] + }, + "Investigation Base": { + "inherits": "Request Base", + "own_attributes": [ + "Target Element", + "Additional Properties" + ] + }, + "Naming Standards Vocabulary Base": { + "inherits": "Request Base", + "own_attributes": [ + "Target Element", + "Additional Properties" + ] } }, "commands": { @@ -5280,6 +5294,82 @@ "bundle": "Declassify Base", "custom_attributes": [], "Journal Entry": "" + }, + "Classify Investigation": { + "display_name": "investigation_classification", + "qn_prefix": "Investigation", + "alternate_names": [], + "family": "Curation", + "description": "Classify an existing Project as an investigation that is being conducted to answer a question or seek out information (0130).", + "verb": "Classify", + "upsert": false, + "attach": false, + "level": "Basic", + "find_method": "", + "find_constraints": "", + "extra_find": "", + "extra_constraints": "", + "OM_TYPE": "Investigation", + "bundle": "Investigation Base", + "custom_attributes": [], + "Journal Entry": "" + }, + "Declassify Investigation": { + "display_name": "investigation_classification", + "qn_prefix": "Investigation", + "alternate_names": [], + "family": "Curation", + "description": "Remove the Investigation classification from a Project.", + "verb": "Declassify", + "upsert": false, + "attach": false, + "level": "Basic", + "find_method": "", + "find_constraints": "", + "extra_find": "", + "extra_constraints": "", + "OM_TYPE": "Investigation", + "bundle": "Declassify Base", + "custom_attributes": [], + "Journal Entry": "" + }, + "Classify Naming Standards Vocabulary": { + "display_name": "naming_standards_vocabulary_classification", + "qn_prefix": "NamingStandardsVocabulary", + "alternate_names": [], + "family": "Curation", + "description": "Classify an existing Glossary as a naming standards vocabulary -- a glossary that describes the terms used in naming standards (0438).", + "verb": "Classify", + "upsert": false, + "attach": false, + "level": "Basic", + "find_method": "", + "find_constraints": "", + "extra_find": "", + "extra_constraints": "", + "OM_TYPE": "NamingStandardsVocabulary", + "bundle": "Naming Standards Vocabulary Base", + "custom_attributes": [], + "Journal Entry": "" + }, + "Declassify Naming Standards Vocabulary": { + "display_name": "naming_standards_vocabulary_classification", + "qn_prefix": "NamingStandardsVocabulary", + "alternate_names": [], + "family": "Curation", + "description": "Remove the NamingStandardsVocabulary classification from a Glossary.", + "verb": "Declassify", + "upsert": false, + "attach": false, + "level": "Basic", + "find_method": "", + "find_constraints": "", + "extra_find": "", + "extra_constraints": "", + "OM_TYPE": "NamingStandardsVocabulary", + "bundle": "Declassify Base", + "custom_attributes": [], + "Journal Entry": "" } } } diff --git a/md_processing/v2/curation.py b/md_processing/v2/curation.py index 73c41676..4aa7a983 100644 --- a/md_processing/v2/curation.py +++ b/md_processing/v2/curation.py @@ -224,6 +224,18 @@ class ClassificationSpec: "DataSharingAgreement": ClassificationSpec( "_async_set_agreement_as_data_sharing_agreement", "_async_clear_agreement_as_data_sharing_agreement", "DataSharingAgreementProperties"), + # Data Standards types (Egeria PR #9300) -- pure marker classifications, no + # custom properties. Investigation (0130 ProjectKind) routed through + # ProjectManager; NamingStandardsVocabulary (0438) routed through + # GlossaryManager (see CURATION_CLASSIFICATION_CLIENTS below). Not yet + # verified against a live server -- the type is not deployed there yet + # (confirmed with the user 2026-09-08); .http ground truth also not yet + # updated in this checkout. + "Investigation": ClassificationSpec( + "_async_set_project_as_investigation", "_async_clear_project_as_investigation", "InvestigationProperties"), + "NamingStandardsVocabulary": ClassificationSpec( + "_async_set_glossary_as_naming_standards_vocabulary", "_async_clear_glossary_as_naming_standards_vocabulary", + "NamingStandardsVocabularyProperties"), } # OM_TYPEs in CLASSIFICATION_METHODS whose set/clear methods live on a client other than @@ -245,6 +257,8 @@ class ClassificationSpec: "ProjectKind": "project_manager", "CollectionKind": "collection_manager", "DataSharingAgreement": "digital_business", + "Investigation": "project_manager", + "NamingStandardsVocabulary": "glossary_manager", } diff --git a/pyegeria/core/_globals.py b/pyegeria/core/_globals.py index 6f4b7912..b94438c4 100644 --- a/pyegeria/core/_globals.py +++ b/pyegeria/core/_globals.py @@ -108,7 +108,7 @@ def resolve_enum(enum_class: type[Enum], value: str | int) -> int | None: MEMBERSHIP_STATUS = ["UNKNOWN", "DISCOVERED", "PROPOSED", "IMPORTED", "VALIDATED", "DEPRECATED", "OBSOLETE", "OTHER"] RELATIONSHIP_TYPES = ["RelatedTerm", "Synonym", "Antonym", "PreferredTerm", "ReplacementTerm", "Translation", "IsA", "ValidValue"] -PROJECT_TYPES=["Project","Campaign","Task","PersonalProject","StudyProject","Experiment"] +PROJECT_TYPES=["Project","Campaign","Task","PersonalProject","StudyProject","Experiment","Investigation"] TEMPLATE_GUIDS: dict[str, str] = {} INTEGRATION_GUIDS: dict[str, str] = {} diff --git a/pyegeria/omvs/classification_explorer.py b/pyegeria/omvs/classification_explorer.py index 472d2d9f..d643c590 100644 --- a/pyegeria/omvs/classification_explorer.py +++ b/pyegeria/omvs/classification_explorer.py @@ -9916,6 +9916,10 @@ async def _async_add_data_scope( "class" : "DataScopeProperties", "dataCollectionStartTime" : "isoTimestamp", "dataCollectionEndTime" : "isoTimestamp", + "dataValidityStartTime" : "isoTimestamp", + "dataValidityEndTime" : "isoTimestamp", + "dataCoverageStartTime" : "isoTimestamp", + "dataCoverageEndTime" : "isoTimestamp", "minLongitude" : 0, "minLatitude" : 0, "maxLongitude" : 0, @@ -9979,6 +9983,10 @@ def add_data_scope( "class" : "DataScopeProperties", "dataCollectionStartTime" : "isoTimestamp", "dataCollectionEndTime" : "isoTimestamp", + "dataValidityStartTime" : "isoTimestamp", + "dataValidityEndTime" : "isoTimestamp", + "dataCoverageStartTime" : "isoTimestamp", + "dataCoverageEndTime" : "isoTimestamp", "minLongitude" : 0, "minLatitude" : 0, "maxLongitude" : 0, @@ -10044,6 +10052,10 @@ async def _async_update_data_scope( "class" : "DataScopeProperties", "dataCollectionStartTime" : "isoTimestamp", "dataCollectionEndTime" : "isoTimestamp", + "dataValidityStartTime" : "isoTimestamp", + "dataValidityEndTime" : "isoTimestamp", + "dataCoverageStartTime" : "isoTimestamp", + "dataCoverageEndTime" : "isoTimestamp", "minLongitude" : 0, "minLatitude" : 0, "maxLongitude" : 0, @@ -10113,6 +10125,10 @@ def update_data_scope( "class" : "DataScopeProperties", "dataCollectionStartTime" : "isoTimestamp", "dataCollectionEndTime" : "isoTimestamp", + "dataValidityStartTime" : "isoTimestamp", + "dataValidityEndTime" : "isoTimestamp", + "dataCoverageStartTime" : "isoTimestamp", + "dataCoverageEndTime" : "isoTimestamp", "minLongitude" : 0, "minLatitude" : 0, "maxLongitude" : 0, diff --git a/pyegeria/omvs/glossary_manager.py b/pyegeria/omvs/glossary_manager.py index 6adf6012..c452d1c1 100644 --- a/pyegeria/omvs/glossary_manager.py +++ b/pyegeria/omvs/glossary_manager.py @@ -625,6 +625,159 @@ def clear_glossary_as_canonical(self, glossary_guid: str, loop = asyncio.get_event_loop() loop.run_until_complete(self._async_clear_glossary_as_canonical(glossary_guid, body)) + @dynamic_catch + async def _async_set_glossary_as_naming_standards_vocabulary(self, glossary_guid: str, + body: Optional[dict | NewClassificationRequestBody] = None) -> None: + """Classify a glossary to declare that it describes the terms used in naming standards. The terms in + this type of glossary are the name parts that are combined to form names that follow the organization's + naming standards. Async version. + + Parameters + ---------- + glossary_guid : str + Unique identifier of the glossary to classify. + body : dict | NewClassificationRequestBody, optional + Full request body. If supplied, overrides other parameters. + + Returns + ------- + None + + Raises + ------ + PyegeriaInvalidParameterException + PyegeriaAPIException + NotAuthorizedException + + Notes + ----- + Example body: + { + "class": "NewClassificationRequestBody", + "properties": { + "class": "NamingStandardsVocabularyProperties" + } + } + """ + url = (f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/glossary-manager/glossaries/" + f"{glossary_guid}/is-naming-standards-vocabulary") + if body is None: + body = { + "class": "NewClassificationRequestBody", + "properties": { + "class": "NamingStandardsVocabularyProperties" + } + } + await self._async_new_classification_request(url, "NamingStandardsVocabularyProperties", body) + logger.info(f"Set glossary {glossary_guid} as naming standards vocabulary") + + @dynamic_catch + def set_glossary_as_naming_standards_vocabulary(self, glossary_guid: str, + body: Optional[dict | NewClassificationRequestBody] = None) -> None: + """Classify a glossary to declare that it describes the terms used in naming standards. The terms in + this type of glossary are the name parts that are combined to form names that follow the organization's + naming standards. + + Parameters + ---------- + glossary_guid : str + Unique identifier of the glossary to classify. + body : dict | NewClassificationRequestBody, optional + Full request body. If supplied, overrides other parameters. + + Returns + ------- + None + + Raises + ------ + PyegeriaInvalidParameterException + PyegeriaAPIException + NotAuthorizedException + + Notes + ----- + Example body: + { + "class": "NewClassificationRequestBody", + "properties": { + "class": "NamingStandardsVocabularyProperties" + } + } + """ + loop = asyncio.get_event_loop() + loop.run_until_complete(self._async_set_glossary_as_naming_standards_vocabulary(glossary_guid, body)) + + @dynamic_catch + async def _async_clear_glossary_as_naming_standards_vocabulary(self, glossary_guid: str, + body: Optional[dict | DeleteClassificationRequestBody] = None) -> None: + """Remove the naming standards vocabulary classification from a glossary. Async version. + + Parameters + ---------- + glossary_guid : str + Unique identifier of the glossary. + body : dict | DeleteClassificationRequestBody, optional + Request body with correlation properties. + + Returns + ------- + None + + Raises + ------ + PyegeriaInvalidParameterException + PyegeriaAPIException + NotAuthorizedException + + Notes + ----- + Example body: + { + "class": "DeleteClassificationRequestBody", + "forLineage": false, + "forDuplicateProcessing": false + } + """ + url = (f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/glossary-manager/glossaries/" + f"{glossary_guid}/is-naming-standards-vocabulary/remove") + await self._async_delete_classification_request(url, body) + logger.info(f"Cleared naming standards vocabulary classification from glossary {glossary_guid}") + + @dynamic_catch + def clear_glossary_as_naming_standards_vocabulary(self, glossary_guid: str, + body: Optional[dict | DeleteClassificationRequestBody] = None) -> None: + """Remove the naming standards vocabulary classification from a glossary. + + Parameters + ---------- + glossary_guid : str + Unique identifier of the glossary. + body : dict | DeleteClassificationRequestBody, optional + Request body with correlation properties. + + Returns + ------- + None + + Raises + ------ + PyegeriaInvalidParameterException + PyegeriaAPIException + NotAuthorizedException + + Notes + ----- + Example body: + { + "class": "DeleteClassificationRequestBody", + "forLineage": false, + "forDuplicateProcessing": false + } + """ + loop = asyncio.get_event_loop() + loop.run_until_complete(self._async_clear_glossary_as_naming_standards_vocabulary(glossary_guid, body)) + # # Terms # diff --git a/pyegeria/omvs/governance_officer.py b/pyegeria/omvs/governance_officer.py index 1460d42f..bc512dff 100644 --- a/pyegeria/omvs/governance_officer.py +++ b/pyegeria/omvs/governance_officer.py @@ -609,6 +609,10 @@ async def _async_create_data_lens(self, body: dict | NewElementRequestBody) -> s "results": [], "dataCollectionStartTime" : "{{$isoTimestamp}}", "dataCollectionEndTime" : "{{$isoTimestamp}}", + "dataValidityStartTime" : "{{$isoTimestamp}}", + "dataValidityEndTime" : "{{$isoTimestamp}}", + "dataCoverageStartTime" : "{{$isoTimestamp}}", + "dataCoverageEndTime" : "{{$isoTimestamp}}", "minLongitude" : 0, "minLatitude" : 0, "maxLongitude" : 0, @@ -690,6 +694,10 @@ def create_data_lens(self, body: dict | NewElementRequestBody) -> str: "results": [], "dataCollectionStartTime" : "{{$isoTimestamp}}", "dataCollectionEndTime" : "{{$isoTimestamp}}", + "dataValidityStartTime" : "{{$isoTimestamp}}", + "dataValidityEndTime" : "{{$isoTimestamp}}", + "dataCoverageStartTime" : "{{$isoTimestamp}}", + "dataCoverageEndTime" : "{{$isoTimestamp}}", "minLongitude" : 0, "minLatitude" : 0, "maxLongitude" : 0, diff --git a/pyegeria/omvs/project_manager.py b/pyegeria/omvs/project_manager.py index e04e2e62..1c4aaea1 100644 --- a/pyegeria/omvs/project_manager.py +++ b/pyegeria/omvs/project_manager.py @@ -20,7 +20,7 @@ from pyegeria.core.utils import body_slimmer, dynamic_catch from loguru import logger -PROJECT_TYPES = ["Project", "Campaign", "StudyProject", "Task", "PersonalProject"] +PROJECT_TYPES = ["Project", "Campaign", "StudyProject", "Task", "PersonalProject", "Experiment", "Investigation"] class ProjectManager(ServerClient): @@ -2537,6 +2537,38 @@ def clear_project_as_experiment(self, project_guid: str, loop = asyncio.get_event_loop() loop.run_until_complete(self._async_clear_project_as_experiment(project_guid, body)) + @dynamic_catch + async def _async_set_project_as_investigation(self, project_guid: str, + body: Optional[dict | NewClassificationRequestBody] = None) -> None: + """Classify a project as an investigation that is seeking to answer a question. Async version.""" + url = f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/project-manager/projects/{project_guid}/investigation" + if body is None: + body = {"class": "NewClassificationRequestBody", "properties": {"class": "InvestigationProperties"}} + await self._async_new_classification_request(url, ["InvestigationProperties"], body) + logger.info(f"Classified project {project_guid} as investigation") + + @dynamic_catch + def set_project_as_investigation(self, project_guid: str, + body: Optional[dict | NewClassificationRequestBody] = None) -> None: + """Classify a project as an investigation that is seeking to answer a question.""" + loop = asyncio.get_event_loop() + loop.run_until_complete(self._async_set_project_as_investigation(project_guid, body)) + + @dynamic_catch + async def _async_clear_project_as_investigation(self, project_guid: str, + body: Optional[dict | DeleteClassificationRequestBody] = None) -> None: + """Remove the investigation classification from a project. Async version.""" + url = f"{self.platform_url}/servers/{self.view_server}/api/open-metadata/project-manager/projects/{project_guid}/investigation/remove" + await self._async_delete_classification_request(url, body) + logger.info(f"Removed investigation classification from project {project_guid}") + + @dynamic_catch + def clear_project_as_investigation(self, project_guid: str, + body: Optional[dict | DeleteClassificationRequestBody] = None) -> None: + """Remove the investigation classification from a project.""" + loop = asyncio.get_event_loop() + loop.run_until_complete(self._async_clear_project_as_investigation(project_guid, body)) + @dynamic_catch async def _async_set_project_as_glossary_project(self, project_guid: str, body: Optional[dict | NewClassificationRequestBody] = None) -> None: diff --git a/sample-data/templates/advanced/Curation/Classify_Investigation.md b/sample-data/templates/advanced/Curation/Classify_Investigation.md new file mode 100644 index 00000000..c12408a5 --- /dev/null +++ b/sample-data/templates/advanced/Curation/Classify_Investigation.md @@ -0,0 +1,98 @@ +___ + +## Classify Investigation +> Classify an existing Project as an investigation that is being conducted to answer a question or seek out information (0130). + +### Target Element +> **Input Required**: True + +> **Attribute Type**: Reference Name + +> **Description**: Qualified name of the existing element being classified or linked. + + +### Journal Entry +> **Input Required**: False + +> **Attribute Type**: Simple + +> **Description**: A text entry into a journal. + + +### Effective From +> **Input Required**: False + +> **Attribute Type**: Simple + +> **Description**: The beginning of when an element is viewable. + + +### Effective Time +> **Input Required**: False + +> **Attribute Type**: Simple + +> **Description**: The time at which an element must be effective in order to be returned by the request. + + +### Effective To +> **Input Required**: False + +> **Attribute Type**: Simple + +> **Description**: The ending time at which an element is visible. + + +### External Source GUID +> **Input Required**: False + +> **Attribute Type**: GUID + +> **Description**: The unique identifier of an external source. + + +### External Source Name +> **Input Required**: False + +> **Attribute Type**: Simple + +> **Description**: The name of an external source + + +### For Duplicate Processing +> **Input Required**: False + +> **Attribute Type**: Bool + +> **Description**: Flag indicating if the request is to support duplicate processing. + + +### For Lineage +> **Input Required**: False + +> **Attribute Type**: Bool + +> **Description**: Flag indicating if the request is to support lineage. + + +### Request ID +> **Input Required**: False + +> **Attribute Type**: Simple + +> **Description**: A user provided or system generated request id for a conversation. + + +### Additional Properties +> **Input Required**: False + +> **Attribute Type**: Dictionary + +> **Description**: Additional Properties allow arbitrary properties not defined in the type definitions to be added to any referenceable element. + +> | Parameter Name | Parameter Value | +> |---|---| +> | example_key | example_value | + + +___ diff --git a/sample-data/templates/advanced/Curation/Classify_Naming_Standards_Vocabulary.md b/sample-data/templates/advanced/Curation/Classify_Naming_Standards_Vocabulary.md new file mode 100644 index 00000000..8b03594d --- /dev/null +++ b/sample-data/templates/advanced/Curation/Classify_Naming_Standards_Vocabulary.md @@ -0,0 +1,98 @@ +___ + +## Classify Naming Standards Vocabulary +> Classify an existing Glossary as a naming standards vocabulary -- a glossary that describes the terms used in naming standards (0438). + +### Target Element +> **Input Required**: True + +> **Attribute Type**: Reference Name + +> **Description**: Qualified name of the existing element being classified or linked. + + +### Journal Entry +> **Input Required**: False + +> **Attribute Type**: Simple + +> **Description**: A text entry into a journal. + + +### Effective From +> **Input Required**: False + +> **Attribute Type**: Simple + +> **Description**: The beginning of when an element is viewable. + + +### Effective Time +> **Input Required**: False + +> **Attribute Type**: Simple + +> **Description**: The time at which an element must be effective in order to be returned by the request. + + +### Effective To +> **Input Required**: False + +> **Attribute Type**: Simple + +> **Description**: The ending time at which an element is visible. + + +### External Source GUID +> **Input Required**: False + +> **Attribute Type**: GUID + +> **Description**: The unique identifier of an external source. + + +### External Source Name +> **Input Required**: False + +> **Attribute Type**: Simple + +> **Description**: The name of an external source + + +### For Duplicate Processing +> **Input Required**: False + +> **Attribute Type**: Bool + +> **Description**: Flag indicating if the request is to support duplicate processing. + + +### For Lineage +> **Input Required**: False + +> **Attribute Type**: Bool + +> **Description**: Flag indicating if the request is to support lineage. + + +### Request ID +> **Input Required**: False + +> **Attribute Type**: Simple + +> **Description**: A user provided or system generated request id for a conversation. + + +### Additional Properties +> **Input Required**: False + +> **Attribute Type**: Dictionary + +> **Description**: Additional Properties allow arbitrary properties not defined in the type definitions to be added to any referenceable element. + +> | Parameter Name | Parameter Value | +> |---|---| +> | example_key | example_value | + + +___ diff --git a/sample-data/templates/advanced/Curation/Declassify_Investigation.md b/sample-data/templates/advanced/Curation/Declassify_Investigation.md new file mode 100644 index 00000000..3033ec9e --- /dev/null +++ b/sample-data/templates/advanced/Curation/Declassify_Investigation.md @@ -0,0 +1,86 @@ +___ + +## Declassify Investigation +> Remove the Investigation classification from a Project. + +### Target Element +> **Input Required**: True + +> **Attribute Type**: Reference Name + +> **Description**: Qualified name of the existing element being classified or linked. + + +### Journal Entry +> **Input Required**: False + +> **Attribute Type**: Simple + +> **Description**: A text entry into a journal. + + +### Effective From +> **Input Required**: False + +> **Attribute Type**: Simple + +> **Description**: The beginning of when an element is viewable. + + +### Effective Time +> **Input Required**: False + +> **Attribute Type**: Simple + +> **Description**: The time at which an element must be effective in order to be returned by the request. + + +### Effective To +> **Input Required**: False + +> **Attribute Type**: Simple + +> **Description**: The ending time at which an element is visible. + + +### External Source GUID +> **Input Required**: False + +> **Attribute Type**: GUID + +> **Description**: The unique identifier of an external source. + + +### External Source Name +> **Input Required**: False + +> **Attribute Type**: Simple + +> **Description**: The name of an external source + + +### For Duplicate Processing +> **Input Required**: False + +> **Attribute Type**: Bool + +> **Description**: Flag indicating if the request is to support duplicate processing. + + +### For Lineage +> **Input Required**: False + +> **Attribute Type**: Bool + +> **Description**: Flag indicating if the request is to support lineage. + + +### Request ID +> **Input Required**: False + +> **Attribute Type**: Simple + +> **Description**: A user provided or system generated request id for a conversation. + + +___ diff --git a/sample-data/templates/advanced/Curation/Declassify_Naming_Standards_Vocabulary.md b/sample-data/templates/advanced/Curation/Declassify_Naming_Standards_Vocabulary.md new file mode 100644 index 00000000..a839f5ae --- /dev/null +++ b/sample-data/templates/advanced/Curation/Declassify_Naming_Standards_Vocabulary.md @@ -0,0 +1,86 @@ +___ + +## Declassify Naming Standards Vocabulary +> Remove the NamingStandardsVocabulary classification from a Glossary. + +### Target Element +> **Input Required**: True + +> **Attribute Type**: Reference Name + +> **Description**: Qualified name of the existing element being classified or linked. + + +### Journal Entry +> **Input Required**: False + +> **Attribute Type**: Simple + +> **Description**: A text entry into a journal. + + +### Effective From +> **Input Required**: False + +> **Attribute Type**: Simple + +> **Description**: The beginning of when an element is viewable. + + +### Effective Time +> **Input Required**: False + +> **Attribute Type**: Simple + +> **Description**: The time at which an element must be effective in order to be returned by the request. + + +### Effective To +> **Input Required**: False + +> **Attribute Type**: Simple + +> **Description**: The ending time at which an element is visible. + + +### External Source GUID +> **Input Required**: False + +> **Attribute Type**: GUID + +> **Description**: The unique identifier of an external source. + + +### External Source Name +> **Input Required**: False + +> **Attribute Type**: Simple + +> **Description**: The name of an external source + + +### For Duplicate Processing +> **Input Required**: False + +> **Attribute Type**: Bool + +> **Description**: Flag indicating if the request is to support duplicate processing. + + +### For Lineage +> **Input Required**: False + +> **Attribute Type**: Bool + +> **Description**: Flag indicating if the request is to support lineage. + + +### Request ID +> **Input Required**: False + +> **Attribute Type**: Simple + +> **Description**: A user provided or system generated request id for a conversation. + + +___ diff --git a/sample-data/templates/basic/Curation/Classify_Investigation.md b/sample-data/templates/basic/Curation/Classify_Investigation.md new file mode 100644 index 00000000..565cce5f --- /dev/null +++ b/sample-data/templates/basic/Curation/Classify_Investigation.md @@ -0,0 +1,22 @@ +___ + +## Classify Investigation +> Classify an existing Project as an investigation that is being conducted to answer a question or seek out information (0130). + +### Target Element +> **Input Required**: True + +> **Attribute Type**: Reference Name + +> **Description**: Qualified name of the existing element being classified or linked. + + +### Journal Entry +> **Input Required**: False + +> **Attribute Type**: Simple + +> **Description**: A text entry into a journal. + + +___ diff --git a/sample-data/templates/basic/Curation/Classify_Naming_Standards_Vocabulary.md b/sample-data/templates/basic/Curation/Classify_Naming_Standards_Vocabulary.md new file mode 100644 index 00000000..1e29644d --- /dev/null +++ b/sample-data/templates/basic/Curation/Classify_Naming_Standards_Vocabulary.md @@ -0,0 +1,22 @@ +___ + +## Classify Naming Standards Vocabulary +> Classify an existing Glossary as a naming standards vocabulary -- a glossary that describes the terms used in naming standards (0438). + +### Target Element +> **Input Required**: True + +> **Attribute Type**: Reference Name + +> **Description**: Qualified name of the existing element being classified or linked. + + +### Journal Entry +> **Input Required**: False + +> **Attribute Type**: Simple + +> **Description**: A text entry into a journal. + + +___ diff --git a/sample-data/templates/basic/Curation/Declassify_Investigation.md b/sample-data/templates/basic/Curation/Declassify_Investigation.md new file mode 100644 index 00000000..6ada98b6 --- /dev/null +++ b/sample-data/templates/basic/Curation/Declassify_Investigation.md @@ -0,0 +1,22 @@ +___ + +## Declassify Investigation +> Remove the Investigation classification from a Project. + +### Target Element +> **Input Required**: True + +> **Attribute Type**: Reference Name + +> **Description**: Qualified name of the existing element being classified or linked. + + +### Journal Entry +> **Input Required**: False + +> **Attribute Type**: Simple + +> **Description**: A text entry into a journal. + + +___ diff --git a/sample-data/templates/basic/Curation/Declassify_Naming_Standards_Vocabulary.md b/sample-data/templates/basic/Curation/Declassify_Naming_Standards_Vocabulary.md new file mode 100644 index 00000000..7fcbd021 --- /dev/null +++ b/sample-data/templates/basic/Curation/Declassify_Naming_Standards_Vocabulary.md @@ -0,0 +1,22 @@ +___ + +## Declassify Naming Standards Vocabulary +> Remove the NamingStandardsVocabulary classification from a Glossary. + +### Target Element +> **Input Required**: True + +> **Attribute Type**: Reference Name + +> **Description**: Qualified name of the existing element being classified or linked. + + +### Journal Entry +> **Input Required**: False + +> **Attribute Type**: Simple + +> **Description**: A text entry into a journal. + + +___