Skip to content

feat(dq): add DQ rule lifecycle + job observability MCP tools - #91

Open
regmimridul wants to merge 21 commits into
mainfrom
DEV-198734
Open

feat(dq): add DQ rule lifecycle + job observability MCP tools#91
regmimridul wants to merge 21 commits into
mainfrom
DEV-198734

Conversation

@regmimridul

@regmimridul regmimridul commented Jul 6, 2026

Copy link
Copy Markdown

🎯 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). monitorType is FREEFORM_SQL (full SQL) or SIMPLE_SQL (single-column check); supports filterQuery, 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, with newMonitorName to 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_sql take edgeSiteId/connectionId/schemaName — the discovery output from prepare_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). Optional runDate/runDateEnd (dateKind DATE/TIMESTAMP) and backrun backfill; defaults to current date/time. Returns the jobRunId.
  • get_dq_job_status — status of a run by jobRunId via 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

  • My code follows the style guidelines of this project.
  • I have performed a self-review of my own code.
  • I have commented my code, particularly in hard-to-understand areas.
  • I have made corresponding changes to the documentation (if needed).
  • My commit messages follow the Conventional Commits standard.

🤖 Generated with Claude Code

@regmimridul
regmimridul requested a review from a team as a code owner July 6, 2026 14:42
regmimridul and others added 2 commits July 8, 2026 10:02
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>
@regmimridul regmimridul changed the title feat(dq): add create_dq_rule + run_dq_job MCP tools feat(dq): add DQ rule lifecycle + job observability MCP tools Jul 13, 2026
regmimridul and others added 8 commits July 13, 2026 12:54
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>
@svc-snyk-github-jira

svc-snyk-github-jira commented Jul 14, 2026

Copy link
Copy Markdown

Snyk checks have passed. No issues have been found so far.

Status Scan Engine Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues
Licenses 0 0 0 0 0 issues
Code Security 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

regmimridul and others added 2 commits July 14, 2026 13:23
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>
@aberkowCollibra

Copy link
Copy Markdown

@regmimridul do we have tests on the DQ side to ensure these API contracts will not change and will fail if someone modifies?

@EricWarnerCollibra

Copy link
Copy Markdown
Contributor

@regmimridul I would have the same comment as here -> #88 (comment)

Comment thread pkg/tools/preview_dq_rule_sql/tool.go Outdated
@@ -0,0 +1,124 @@
// Package preview_dq_rule_sql implements the preview_dq_rule_sql MCP tool: it

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

regmimridul and others added 2 commits July 15, 2026 12:24
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>
@regmimridul

Copy link
Copy Markdown
Author

@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.

@regmimridul
regmimridul marked this pull request as draft July 16, 2026 15:24
regmimridul and others added 6 commits July 16, 2026 11:33
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
@regmimridul
regmimridul marked this pull request as ready for review July 28, 2026 15:05

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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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:

Suggested change
(validate → create → runobserve, edit/delete). This workbench reuses those
(validate → create → inspectread 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) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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:

  • monitorName matches ^[A-Za-z0-9_-]{1,256}$
  • description ≤ 256 chars
  • monitorType == SIMPLE_SQLcolumnName required — assuming the API does require it (the schema currently says "Optional… used with SIMPLE_SQL rules"; worth confirming which is true and aligning)

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.

5 participants