feat(dq): add DQ rule lifecycle + job observability MCP tools - #91
feat(dq): add DQ rule lifecycle + job observability MCP tools#91regmimridul wants to merge 21 commits into
Conversation
# Conflicts: # pkg/tools/register.go
Add tools to manage a DQ rule's full lifecycle and observe job runs:
get_dq_rule, edit_dq_rule, delete_dq_rule (rule CRUD); get_dq_rule_results
(per-run results/breaks); validate_dq_rule + preview_dq_rule_sql (catch a bad
rule before running); get_dq_job_status + get_dq_job_log (observe the run).
Rule/results/validate/preview use the internal DQ monitoring API; job status
uses the public /rest/dq/1.0/jobRuns/{jobRunId}; job log uses the internal
surface (no public log endpoint exists).
Refs: DEV-198734
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Guides the agent through the DQ rule workflow: prepare_create_dq_job for discovery ids, validate_dq_rule BEFORE create_dq_rule (catch bad SQL up front), then run_dq_job and observe via get_dq_job_status / get_dq_job_log / get_dq_rule_results. Documents the PUSHDOWN-only constraint, the FREEFORM_SQL/ SIMPLE_SQL enum, full-replace edit semantics, and destructive delete. Registers it in the collibra/index navigator. Refs: DEV-198734 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Instruct the agent to source a meaningful monitorName from the user (not an opaque auto-name) and, for SIMPLE_SQL rules, to ask for the target columnName. Refs: DEV-198734 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add tools for the DQ rule-template workbench:
- list_dq_rule_templates: list built-in (OOTB) + custom templates with filters
- get_dq_rule_template: read one template by id
- deploy_dq_rule_template: instantiate a template as concrete rules across
job/column targets (bulk), server-resolved dialect SQL, {template}_{column}
naming
Templates use the internal DQ API (/rest/dq/internal/v1/rules/templates). Note:
the DQ service exposes no template/data-type compatibility endpoint, so
incompatible combinations surface as deploy errors rather than being pre-flagged.
Refs: DEV-198734
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- generate_dq_rule_sql: turn a plain-language check into rule SQL via the internal DQ AI endpoint (POST /rest/dq/internal/v1/ai/text2sql). Returns a single SQL string (no separate filter clause); needs edgeSiteId/connectionId. - find_dq_rules: search existing rules (monitors) via the monitoring dashboard (POST /rest/dq/internal/v1/monitoring/monitors/dashboard), filtering by JOB_NAME/COLUMN_NAME/MONITOR_NAME — used for duplicate detection on a column. Both use the internal DQ API. Text2SQL is not in the OAS spec (hand-written client). Refs: DEV-198734 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Multi-turn flow to author DQ rules across many catalog columns: target columns (search or explicit) -> confirm -> define via template (deploy_dq_rule_template) or plain-language (generate_dq_rule_sql) -> validate/preview loop -> job assignment (prepare_create_dq_job/create_dq_job) -> confirm -> bulk execute with partial success, then observe. Reuses find_dq_rules for duplicate detection and edit_asset for catalog associations. Honestly documents current limitations: column search only supports Domain/Community/assetType as structured filters (rest via free-text/explicit); no template/data-type compatibility API; Text2SQL returns a single SQL string. Registers it in the collibra/index navigator. Refs: DEV-198734 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Align the skill with actual tool capabilities: notifications are job-level (create_dq_job), not per-rule (create_dq_rule has no notifications field); tolerance is a breaking-record count, not the ticket's "Tolerance %"; and the template deploy path inherits settings from the template rather than accepting per-target settings. Adds these to the known-limitations list. Refs: DEV-198734 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
In the workbench final-confirmation step, show the chosen template once with its
target columns grouped by job (rule name {template}_{column} per column) instead
of a flat list of template x column pairs. Plain-language path still lists one
entry per rule since each SQL can differ.
Refs: DEV-198734
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…plate Both write tools now enforce a review-before-write gate: confirm=false (default) returns a preview (create_dq_rule echoes the composed rule + SQL; deploy echoes the template id + targets) and writes nothing; confirm=true performs the write. This makes "review the SQL before saving" tool-enforced rather than skill guidance. Updates dq-rules and dq-rule-workbench skills + README to match. Refs: DEV-198734 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
✅ Snyk checks have passed. No issues have been found so far.
💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse. |
Find catalog Column assets by metadata the public REST search can't filter on — Description/Data Type attribute values, a Data Steward role, and relations to a Business Term / Business Rule / Data Element / Data Attribute (by name), AND-combined. Uses the DGC Knowledge Graph API (POST /graphql/knowledgeGraph/v1) with an AssetFilter built and chained via `_and`; relation filters use the OOTB system relation-type public ids (confirmed in pg-dgc). Query shapes verified live against the deployed KG schema. Requires the KG endpoint to be enabled on the instance. Classification-tag filtering is not supported (no KG predicate). Built against the deployed KG schema; other KG versions may differ. Refs: DEV-198734 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Column targeting now uses search_catalog_columns for the metadata filters (description, data type, data-steward role, business term/rule, data element/attribute). Rule 9 rewritten: KG API required, Classification Tags unsupported, timeout on broad lone filters, fallback to search_asset_keyword. Refs: DEV-198734 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
@regmimridul do we have tests on the DQ side to ensure these API contracts will not change and will fail if someone modifies? |
|
@regmimridul I would have the same comment as here -> #88 (comment) |
| @@ -0,0 +1,124 @@ | |||
| // Package preview_dq_rule_sql implements the preview_dq_rule_sql MCP tool: it | |||
There was a problem hiding this comment.
I recommend not including this endpoint since it returns live client data. I'm not sure if the results get passed into the LLM and we'd need to verify before we can go down this path.
Per PR review feedback (mirrored from PR 88): explain Collibra-coded terms so an LLM with no Collibra knowledge can use the tools. Gloss job/dataset, rule/monitor, jobRunId, edge/edgeSiteId/connectionId, dimensions, backrun, OOTB, tolerance, and FREEFORM_SQL/SIMPLE_SQL in each tool's Description and jsonschema fields, keeping the original terms so they still match. Descriptions/field docs only — no behavior, names, or logic changed. Refs: DEV-198734 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Drop preview_dq_rule_sql: it executed a rule's SQL against the source and returned actual sample rows, which would send live client data into the LLM. validate_dq_rule (validity + message, no row data) remains as the safe pre-flight. Removes the tool package, its client function PreviewDQRuleSQL and DQPreview* types (PreviewRuleRequest kept for validate_dq_rule), the registration, README entry, and skill references. Refs: DEV-198734 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
@aberkowCollibra @EricWarnerCollibra removed the preview_dq_rule_sql endpoint and updated the PR to use less of Collibra jargon. Will be adding tests to ensure that the API contracts do not change shortly. |
Per scope decision, drop out-of-scope capabilities: editing/deleting existing rules and triggering/observing job runs. Removes edit_dq_rule, delete_dq_rule, run_dq_job, get_dq_job_status, get_dq_job_log (tool packages), their client functions (EditDQRule/DeleteDQRule from dq_rules_client.go; the whole dq_jobs_client.go), registrations, README entries, and skill references. Kept get_dq_rule_results (read-only; reads results of runs triggered elsewhere). Remaining DQ rule surface: create_dq_rule, get_dq_rule, validate_dq_rule, get_dq_rule_results, find_dq_rules, list/get/deploy templates, generate_dq_rule_sql, search_catalog_columns. Refs: DEV-198734 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
# Conflicts: # README.md # pkg/tools/register.go
Mirror PR 88: put all PR 91 DQ tools (create/get/validate rules, results, templates list/get/deploy, generate_dq_rule_sql, find_dq_rules, search_catalog_columns) behind the shared `data-quality` experimental feature — off by default. Adds DataQualityFeatureName, gates the registrations, and registers the feature in knownExperimentalFeatures so --experimental/help/config recognize it. Refs: DEV-198734 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… API Replicate remaining PR 88 conventions in the DQ rule tools: - Rename MCP tool NAMES from the `dq` abbreviation to spelled-out `data_quality` (e.g. create_data_quality_rule), matching PR 88's create_data_quality_job. Package dirs / identifiers unchanged; only Name strings + prose (descriptions, README, skills) updated. - Add register_test.go gating cases asserting the DQ tools are hidden by default and visible only with the `data-quality` experimental feature. - Switch the rule-template tools (list/get/deploy) from the internal id-keyed API to the PUBLIC name-keyed API (/rest/dq/1.0/ruleTemplates), per PR 88's prefer-public direction. Templates are now keyed by ruleTemplateName; isSystem replaces ootb; deploy is partial-success (per-target outcomes). Refs: DEV-198734 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
# Conflicts: # cmd/chip/experimental.go # pkg/tools/register.go # pkg/tools/register_test.go
|
|
||
| Relationship to the other DQ skills: | ||
| - **`collibra/dq-rules`** — the mechanics of a single rule on an existing job | ||
| (validate → create → run → observe, edit/delete). This workbench reuses those |
There was a problem hiding this comment.
This says collibra/dq-rules covers "run → observe, edit/delete", but that skill explicitly states it does not cover editing, deleting, or triggering runs — and no edit/delete/run tools exist in this PR. One of the two files is wrong (the code matches dq-rules). Suggest:
| (validate → create → run → observe, edit/delete). This workbench reuses those | |
| (validate → create → inspect → read results). This workbench reuses those |
| } | ||
|
|
||
| // CreateDQRule creates a data quality rule (monitor) on an existing DQ job. | ||
| func CreateDQRule(ctx context.Context, client *http.Client, request CreateDQRuleRequest) (*CreateDQRuleResponse, error) { |
There was a problem hiding this comment.
CreateDQRule hand-rolls the marshal → request → read cycle that dqDo (in this same file) already encapsulates — it looks like it predates the helper and never got refactored. Rewriting it on top of dqDo removes ~35 lines while keeping the status-mapping switch intact:
func CreateDQRule(ctx context.Context, client *http.Client, request CreateDQRuleRequest) (*CreateDQRuleResponse, error) {
respBody, status, err := dqDo(ctx, client, http.MethodPost, "/rest/dq/internal/v1/monitoring/monitor", request)
if err != nil {
return nil, fmt.Errorf("creating dq rule: %w", err)
}
if status != http.StatusOK {
switch status {
case http.StatusBadRequest:
return nil, fmt.Errorf("creating dq rule: bad request (invalid rule definition): %s", string(respBody))
// ... same cases as today
}
}
var result CreateDQRuleResponse
if err := json.Unmarshal(respBody, &result); err != nil {
return nil, fmt.Errorf("creating dq rule: decoding response: %w", err)
}
return &result, nil
}| opContains = "CONTAINS" | ||
| ) | ||
|
|
||
| // Input is the tool's typed input. At least one filter should be provided; for |
There was a problem hiding this comment.
The comment says "At least one filter should be provided", but the handler doesn't enforce it — a call with no filters posts an empty filter list and pages through every monitor on the instance. search_catalog_columns enforces its equivalent rule with a validation_error.
Either add the same guard here, or — if list-all is intentional — drop the sentence so the doc matches the behavior.
| } | ||
|
|
||
| // RulePreview is the composed rule echoed back for review when confirm is false. | ||
| type RulePreview struct { |
There was a problem hiding this comment.
The preview omits Description and TemplateID, both of which are sent on create — so what the user approves at the checkpoint isn't the complete rule. Since the whole point of confirm=false is faithful review, consider echoing every field of the composed request.
|
|
||
| // validate enforces the required fields and the monitorType enum before any | ||
| // network call, so the agent gets a cheap, self-correcting error. | ||
| func validate(input Input) *Output { |
There was a problem hiding this comment.
The dq-rules skill promises "Names allow only letters, digits, - and _" (max 256) and the schema says description is max 256 chars — but validate() checks neither, so those mistakes only surface as downstream 400s. Cheap pre-flight checks would keep errors descriptive and self-correcting for the agent:
monitorNamematches^[A-Za-z0-9_-]{1,256}$description≤ 256 charsmonitorType == SIMPLE_SQL⇒columnNamerequired — assuming the API does require it (the schema currently says "Optional… used with SIMPLE_SQL rules"; worth confirming which is true and aligning)
🎯 What does this PR do?
Adds MCP tools to author, manage and observe data-quality rules and job runs on an existing DQ job (DEV-198734). Together they cover a rule's full lifecycle: preview/validate → create → read → edit → delete, plus run the job and observe the outcome.
Rule authoring & lifecycle (CRUD)
create_dq_rule— create a rule (monitor) on a job via the DQ monitoring API (POST /rest/dq/internal/v1/monitoring/monitor).monitorTypeisFREEFORM_SQL(full SQL) orSIMPLE_SQL(single-column check); supportsfilterQuery,columnName,dimensions,tolerance, and template linkage. Defaults to active and not suppressed.get_dq_rule— read a single rule's definition (GET /rest/dq/internal/v1/jobs/{jobName}/monitors/rules/{monitorName}).edit_dq_rule— update an existing rule; full-replace, withnewMonitorNameto rename (PUT /rest/dq/internal/v1/monitors/rules).delete_dq_rule— delete a rule from a job (DELETE /rest/dq/internal/v1/jobs/{jobName}/monitors/rules/{monitorName}). Marked destructive.Pre-flight & results
validate_dq_rule— validate a rule's SQL/definition before saving or running, so a malformed rule is caught up front (POST /rest/dq/internal/v1/rules/validate).preview_dq_rule_sql— run the rule's SQL and return sample columns + rows (POST /rest/dq/internal/v1/rules/previewRule).get_dq_rule_results— per-run results after a job run: score, breaking/passing counts, pass/fail, exceptions; paginated (GET /rest/dq/internal/v1/monitoring/rules/{jobName}/{ruleName}).(
validate_dq_rule/preview_dq_rule_sqltakeedgeSiteId/connectionId/schemaName— the discovery output fromprepare_create_dq_job.)Job run & observability
run_dq_job— trigger a run of an existing job, executing its rules (POST /rest/dq/1.0/jobs/{jobName}/run). OptionalrunDate/runDateEnd(dateKindDATE/TIMESTAMP) andbackrunbackfill; defaults to current date/time. Returns thejobRunId.get_dq_job_status— status of a run byjobRunIdvia the public API (GET /rest/dq/1.0/jobRuns/{jobRunId}): run status (RUNNING/FINISHED/FAILED…), activity, score, breaking-monitor count, failure exception.get_dq_job_log— execution log for a run (stages, timings, exceptions). Uses the internal DQ UI surface (GET /rest/dq/internal/v1/job/logs?jobUUID={jobRunId}) — the public DQ API has no log endpoint.All tools validate inputs before any call, surface downstream DQ errors (400/403/404/422) as structured results, and are covered by unit tests. API contracts were taken from the
dq(udq-app) controllers/OAS, not guessed. README updated with all entries.Refs: DEV-198734
✅ Checklist
🤖 Generated with Claude Code