Skip to content

QUA-1765: Update CLI according to the latest changes#48

Merged
shindiogawa merged 4 commits into
mainfrom
qua-1735-rename-inference-threshold-to-ai-effort
May 8, 2026
Merged

QUA-1765: Update CLI according to the latest changes#48
shindiogawa merged 4 commits into
mainfrom
qua-1735-rename-inference-threshold-to-ai-effort

Conversation

@gasscoelho
Copy link
Copy Markdown
Contributor

@gasscoelho gasscoelho commented May 5, 2026

Linear

Ref QUA-1765
Ref QUA-1735
Ref QUA-1652
Ref QUA-1646
Ref QUA-1408

Overview

Aligns the CLI with the UI vocabulary refresh around AI-driven profiling and rounds out CLI coverage for several other recent controlplane API additions. Everything is additive — no breaking changes, no removed flags. Existing scripts continue to work.

Key Changes

Profile operations: AI effort levels

  • New --ai-effort flag on qualytics operations profile, accepting labeled values (off, low, medium, high, xhigh, max) instead of an opaque 0–5 integer:

    qualytics operations profile --datastore-id 1 --ai-effort high
  • --inference-threshold kept as a deprecated alias (hidden=True, so it no longer clutters --help output). Existing CI/CD pipelines keep working — they just emit a one-line deprecation warning:

    qualytics operations profile --datastore-id 1 --inference-threshold 3
    # ⚠ --inference-threshold is deprecated; use --ai-effort instead.
  • Client-side numeric normalization via _normalize_ai_effort() maps legacy integers (05) to their label equivalents (off, low, medium, high, xhigh, max) before the request leaves the CLI. The wire format is always the new labeled value, so the CLI keeps working even if the server eventually drops its own backfill alias.

  • Case-insensitive validation--ai-effort HIGH, --ai-effort high, and --ai-effort High behave identically. Invalid values fail fast with a clear error.

  • Terminology refresh — help text and docs updated from "inferred checks" to "AI managed checks" to match the UI.

Legacy value New label
0 off
1 low
2 medium
3 high
4 xhigh
5 max

Scan operations: auto-resolve passed anomalies

When a scan completes, open anomalies whose fingerprints no longer fail can now be auto-resolved.

# Disable auto-resolution for this scan
qualytics operations scan --datastore-id 1 --no-auto-resolve-passed-anomalies

# Explicitly enable (matches server default)
qualytics operations scan --datastore-id 1 --auto-resolve-passed-anomalies

Tri-state: when omitted, the server default (currently on) takes effect. Auto-resolution is silently skipped for incremental scans server-side regardless of the flag.

Connections: IAM Role authentication for S3, Athena, and Redshift

Authenticate AWS-backed datastores with an IAM Role instead of static access keys.

# S3 with IAM Role
qualytics connections create \
  --type s3 \
  --name s3-prod \
  --uri s3://my-bucket \
  --authentication-type IAM_ROLE \
  --role-arn arn:aws:iam::123456789012:role/QualyticsReader \
  --external-id my-external-id

# Athena with IAM Role
qualytics connections create \
  --type athena \
  --name athena-prod \
  --authentication-type IAM_ROLE \
  --role-arn arn:aws:iam::123456789012:role/QualyticsAthena

Default authentication is SHARED_KEY for S3, BASIC for Athena/Redshift — no change for existing users. The CLI fails fast with a clear error if --authentication-type IAM_ROLE is used without --role-arn, so you don't wait on a server round-trip to find out.

Quality checks: ownership and default assignees

Each quality check can now have an owner and a default anomaly assignee.

# Apply an owner to every check in a bulk import
qualytics checks create --datastore-id 1 --file checks.yaml --owner-id 7

# Update an existing check's assignee
qualytics checks update --id 42 --file check.yaml --default-anomaly-assignee-id 12

# Clear ownership (pass 0)
qualytics checks update --id 42 --file check.yaml --owner-id 0

User IDs come from qualytics users list. Ownership is environment-specific and intentionally not carried in checks export YAML — apply it at import time per environment.

Anomalies: assignees on update

Set or clear assignees on individual or batches of anomalies.

# Single anomaly, multiple assignees
qualytics anomalies update --id 42 --status Active --assignee-ids "7,12"

# Bulk-assign a reviewer
qualytics anomalies update --ids 42,43,44 --status Active --assignee-ids "7"

# Clear assignees
qualytics anomalies update --id 42 --status Active --assignee-ids ""

Anomalies: filter by source-record enrichment

# Only anomalies whose source records were enriched
qualytics anomalies list --datastore-id 1 --source-enriched

# Only anomalies whose source records were NOT enriched
qualytics anomalies list --datastore-id 1 --no-source-enriched

Tri-state — omit the flag for no filter.

Configurable request timeout

The CLI's request timeout was hard-coded at 30 seconds, which wasn't enough for some long-running list endpoints on slow networks.

# Per-command override
QUALYTICS_TIMEOUT=120 qualytics datastores list

# Persistent — add to ~/.qualytics/config.yaml
timeout: 120

qualytics auth status now displays the resolved timeout so you can confirm what's in effect:

URL:              https://app.qualytics.io
Status:           Logged in
Token:            eyJh****************
Expiry:           Token expires in 29 day(s) (2026-06-06 12:00 UTC)
SSL Verification: enabled
Request timeout:  120s
Config file:      /Users/you/.qualytics/config.yaml

Cleaner network-error messages

Network errors no longer dump a stack trace. You now get a one-line message:

Request to https://app.qualytics.io/api/datastores timed out after 30s.
Increase the timeout via QUALYTICS_TIMEOUT=<seconds> or set 'timeout' in
~/.qualytics/config.yaml.

Covers timeouts, connection failures, and SSL handshake errors.

- Rename --inference-threshold flag to --ai-effort (keep old as deprecated alias)
- Change ai_effort type from int to str to accept labeled scale (off, low, medium, high, xhigh, max)
- Add _normalize_ai_effort() to convert legacy numeric strings (0-5) for backward compat
- Update docs and help text to use "AI managed checks" terminology
- Add tests for normalization and legacy numeric input handling
@gasscoelho gasscoelho self-assigned this May 5, 2026
@gasscoelho gasscoelho marked this pull request as ready for review May 5, 2026 13:57
@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented May 5, 2026

Greptile Summary

This PR aligns the CLI vocabulary with the UI's AI-driven profiling refresh and rounds out several API additions: --ai-effort replaces --inference-threshold (kept as a hidden deprecated alias with a warning), --auto-resolve-passed-anomalies adds tri-state scan control, IAM Role auth lands for S3/Athena/Redshift, and anomaly/check ownership and assignee fields are wired through.

  • --ai-effort flag: accepts labeled values (off\u2013max) with case-insensitive validation; legacy integers are normalized in _normalize_ai_effort before the request is sent, and the deprecated --inference-threshold emits a one-line warning.
  • IAM Role connections: auth fields are nested under parameters (matching the controlplane wire format) with fast-fail validation when --role-arn is missing.
  • auto_resolve_passed_anomalies in run_scan: the field is unconditionally included in the payload dict even when None, sending null to the API instead of omitting the key \u2014 this contradicts the documented tri-state intent and causes the newly added assert \"auto_resolve_passed_anomalies\" not in payload assertion to fail.

Confidence Score: 4/5

Safe to merge after fixing the scan payload to omit auto_resolve_passed_anomalies when not provided.

The scan service unconditionally includes auto_resolve_passed_anomalies: null in the payload instead of omitting the key, which both sends unintended data to the API and breaks the newly added test assertion that verifies the key is absent by default. All other changes are well-implemented and tested.

qualytics/services/operations.py (scan payload builder) and tests/test_operations.py (the assert "auto_resolve_passed_anomalies" not in payload assertion).

Important Files Changed

Filename Overview
qualytics/services/operations.py Adds _normalize_ai_effort for legacy int→label conversion and auto_resolve_passed_anomalies to the scan payload; the scan field is unconditionally included even when None, contradicting the documented tri-state intent and breaking the matching test assertion.
qualytics/cli/operations.py Adds --ai-effort flag with case-insensitive validation, keeps --inference-threshold as a hidden deprecated alias with a deprecation warning, and adds --auto-resolve-passed-anomalies tri-state flag — all cleanly implemented.
qualytics/api/client.py Introduces _resolve_timeout with env-var/config/default precedence, surfaces cleaner Timeout exception messages using kwargs['timeout'] (always set via setdefault before the request), and passes the resolved timeout to QualyticsClient.
qualytics/services/connections.py Adds IAM Role support for S3/Athena/Redshift by nesting auth fields under parameters, with _require_role_arn_for_iam_role fast-fail validation on both create and update paths.
qualytics/services/quality_checks.py Introduces _user_ref sentinel pattern to distinguish "not provided" from "clear" (0/falsy), then wires owner_id and default_anomaly_assignee_id into both create and update payload builders.
qualytics/cli/anomalies.py Adds --source-enriched/--no-source-enriched tri-state filter and --assignee-ids (with empty-string clear semantics) to the anomalies CLI; parsing and payload construction are correct.
tests/test_operations.py New tests cover _normalize_ai_effort, deprecated flag path, case-insensitive --ai-effort, and auto_resolve_passed_anomalies; however, the assertion assert "auto_resolve_passed_anomalies" not in payload in the default-scan test will fail because the service always includes the key.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["CLI: --ai-effort / --inference-threshold"] --> B{Flag used?}
    B -->|"--inference-threshold N"| C[Emit deprecation warning\nassign to ai_effort]
    B -->|"--ai-effort LABEL"| D[Lowercase + validate\nagainst _VALID_AI_EFFORT]
    C --> D
    D --> E["run_profile(ai_effort=...)"]
    E --> F["_normalize_ai_effort()\n'3' → 'high', labels pass through"]
    F --> G[POST /operations\nai_effort: 'high']

    H["CLI: --auto-resolve-passed-anomalies\n/ --no-... / omit"] --> I{Value?}
    I -->|True| J["payload['auto_resolve_passed_anomalies'] = True"]
    I -->|False| K["payload['auto_resolve_passed_anomalies'] = False"]
    I -->|"None (omit)"| L["BUG: key still sent as null\nshould be omitted"]
    J --> M[POST /operations]
    K --> M
    L --> M

    N["CLI: --authentication-type IAM_ROLE\n--role-arn ARN"] --> O{role_arn present?}
    O -->|No| P[ValueError → Exit 1]
    O -->|Yes| Q["Nest under payload.parameters\n{authentication_type, role_arn, external_id}"]
    Q --> R[POST /datastores or PATCH /datastores/id]
Loading

Reviews (3): Last reviewed commit: "Conver latest release + docs" | Re-trigger Greptile

Comment thread qualytics/cli/operations.py
Comment thread qualytics/cli/operations.py Outdated
Comment thread tests/test_operations.py
@gasscoelho
Copy link
Copy Markdown
Contributor Author

@greptile review

@shindiogawa
Copy link
Copy Markdown
Contributor

@greptile review

Comment thread qualytics/services/operations.py
@gasscoelho gasscoelho changed the title QUA-1735: Rename inference threshold to AI Effort for profile operations QUA-1765: Update cli according to the latest changes May 8, 2026
@gasscoelho gasscoelho changed the title QUA-1765: Update cli according to the latest changes QUA-1765: Update CLI according to the latest changes May 8, 2026
@shindiogawa shindiogawa merged commit dd94d86 into main May 8, 2026
13 checks passed
@gasscoelho gasscoelho deleted the qua-1735-rename-inference-threshold-to-ai-effort branch May 8, 2026 15:32
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.

3 participants